mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-01-30 21:01:07 +02:00
update making-of
This commit is contained in:
parent
c2dbe6e1e9
commit
bfc65c7e9a
@ -349,11 +349,13 @@ This worked well. Now I expected to get a timer interrupt soon after jumping
|
||||
to the idle task. After all, I have set up the compare register, the timer
|
||||
should be running and I enabled the interrupts. However, nothing happened. I
|
||||
looked at the contents of the count register, and found that it was 0. This
|
||||
means that it is not actually counting at all. Looking at the Linux sources,
|
||||
they don't use this timer either, but instead use the cpu-external (but
|
||||
integrated in the chip) timer. The documentation says that they have a
|
||||
different reason for this than a non-functional cpu timer. Still, it means it
|
||||
can be used as an alternative.
|
||||
means that it is not actually counting at all.\footnote{I also checked the
|
||||
random register, which didn't seem to change either. This is a huge
|
||||
performance problem, but it is easily solved by changing the random register
|
||||
manually.} Looking at the Linux sources, they don't use this timer either, but
|
||||
instead use the cpu-external (but integrated in the chip) timer. The
|
||||
documentation says that they have a different reason for this than a
|
||||
non-functional cpu timer. Still, it means it can be used as an alternative.
|
||||
|
||||
Having a timer is important for preemptive multitasking: a process needs to be
|
||||
interrupted in order to be preempted, so there needs to be a periodic interrupt
|
||||
@ -476,7 +478,13 @@ enough to spend kernel space on. But I can change my mind on that later.
|
||||
The last thing to do for now is allowing a memory to be listed. That is,
|
||||
having a suitably priviledged capability to a Memory should allow a program to
|
||||
see what's in it. In particular, what objects it holds, and where pages are
|
||||
mapped. Probably also what messages are in a receiver's queue.
|
||||
mapped. Probably also what messages are in a receiver's queue. For now, I
|
||||
postponsed the actual implementation of this, but I have reserved the code.
|
||||
This is possibly the hardest kernel operation to implement, because a list of
|
||||
items does not have a hard limit on its size. For other operations, it is
|
||||
possible to return a value in a register, or in a page (which needs to be
|
||||
provided by the caller). But in this case, that is not guaranteed to be
|
||||
possible. So I need to think about how to do this.
|
||||
|
||||
\section{A name for the kernel}
|
||||
However, at this point I am publishing the existence of the kernel, and so I
|
||||
@ -488,4 +496,86 @@ logo which is furrier than a winged boot or staff. So I chose Iris, who is
|
||||
also a messenger of gods, but she has a rainbow symbol. This is much nicer for
|
||||
creating a logo.
|
||||
|
||||
\section{Device drivers}
|
||||
It's time to do some real testing of the kernel. So I've read the Linux
|
||||
keyboard driver source, and implemented the same functionality in a boot
|
||||
thread. During kernel load, several boot threads are started. At first, it is
|
||||
just this one.
|
||||
|
||||
The keyboard of the device is like any other keyboard, except that it doesn't
|
||||
have a keyboard controller. So the cpu must do this task itself. A keyboard
|
||||
is built as a matrix of copper wires, organised in rows and columns. Every
|
||||
intersection is a key. Pressing the key makes a connection between the row and
|
||||
the column wire. In the Trendtac, there are 8 rows and 17 columns. All of
|
||||
these lines go to a general purpose input/output pin on the cpu. The keyboard
|
||||
driver sets 0 volt on each column in turn, and reads the rows, which are set as
|
||||
pull-up inputs. If they are not connected, the pull-up makes them return 1.
|
||||
But if the key of the column which is scanned is pressed, the 0 is connected to
|
||||
the row line and 0 is read out. Thus the entire keyboard can be read.
|
||||
|
||||
Linux does all this in kernel space. That means it can access the GPIO ports
|
||||
in kseg2 (unmapped and uncached physical memory). In user space, this is not
|
||||
possible. User space programs can only use mapped memory. So the page with
|
||||
the GPIO ports needs to be mapped to the device driver's address space. For
|
||||
this, I added an operation to the thread capability. Not because it has
|
||||
something to do with a thread, but because every process has its own thread
|
||||
capability, so no special other capability is needed. I'm adding some more
|
||||
priviledged operations while I'm at it: allocate physical memory to a Page
|
||||
object is what I need here. Make a thread ``priviledged'', which means it can
|
||||
use coprocessor 0, and perform these operations. Get a capability for the top
|
||||
memory. Register an interrupt handler. I think these should be enough, but I
|
||||
can always add more, because threads don't need so many operations. I also
|
||||
added a debug operation, which blinks the lock leds. This operation will be
|
||||
removed once the display is working.
|
||||
|
||||
Writing the keyboard driver was as easy as could be expected: I had some
|
||||
problems with the meaning of the bits in the registers (does 1 mean input or
|
||||
output?), and for some reason the above scheme was needed and doing the other
|
||||
way (scanning the rows and reading the columns) didn't work. But for the rest,
|
||||
it wasn't very troublesome. And I was happy to see that it is indeed possible
|
||||
to address device memory through the tlb (so using a mapping). Had that not
|
||||
been possible, then the device drivers would have been forced into the kernel.
|
||||
|
||||
The resulting keyboard driver uses maximum cpu time, because I don't have a
|
||||
timer interrupt yet, and it flashes the leds when a key is pressed or released,
|
||||
without telling which key it was. The final driver will be much better. Of
|
||||
course it will send messages for key events instead of flashing the leds. It
|
||||
will also be interrupt-driven: when no keys are pressed, all columns will be
|
||||
set to 0, and all rows will be set to input with pull-up enabled and interrupt
|
||||
on falling edge. Then no scanning is required. When a key is pressed, the
|
||||
keyboard will be scanned periodically (on the timer interrupt) until no key is
|
||||
pressed anymore. It is not possible to use an interrupt-driven approach while
|
||||
a key is pressed, because there is no way to set up the lines such that there
|
||||
will always be a change when a key is pressed or released. That's not a
|
||||
problem: scanning doesn't take much time, and when the keyboard is being used,
|
||||
the machine is active anyway. While no keys are pressed it makes sense to
|
||||
minimize power consumption, so then the interrupt-driven approach is more
|
||||
important.
|
||||
|
||||
\section{Display driver}
|
||||
The next thing to write is a display driver. With a keyboard and a display, it
|
||||
starts to look like a real computer. However, this proved to be a lot harder
|
||||
than I expected.
|
||||
|
||||
First of all, it wasn't entirely clear which part of the Linux driver I needed
|
||||
to copy. It has support for many displays on all kinds of mips devices, and I
|
||||
only want support for the hardware in the machine. After some searching, it
|
||||
seems that the Trendtac uses the ``pmpv1'' settings.
|
||||
|
||||
Now the display consists of two parts: the pixels and the backlight. I started
|
||||
with the easy part, the backlight. It is connected to a pulse-width-modulator
|
||||
(pwm) of the cpu. This means that the cpu has some logic to make very fast
|
||||
pulses of well-defined width. Connecting this to a light allows software to
|
||||
set the intensity of the output. This means the backlight can be dimmed.
|
||||
|
||||
That's nice. Or well, it should be. When copying the Linux code, I can switch
|
||||
the backlight on and off, but the pwm doesn't seem to work. That's the third
|
||||
counter\footnote{a pwm is implemented using a counter to determine the pulse
|
||||
width} that doesn't count: the count register, the random register and the pwm.
|
||||
|
||||
\section{Clocks}
|
||||
Because this didn't feel good, I decided to implement the timer interrupt
|
||||
first. I copied some code for it from Linux and found, as I feared, that it
|
||||
didn't give any interrupts. I suppose the os timer isn't running either.
|
||||
|
||||
\end{document}
|
||||
|
Loading…
x
Reference in New Issue
Block a user