13.4.6. Writing the device drivers

Writing device drivers for your hardware is the main area of the porting operation, and is completely application dependent. The device drivers provided with the PID Angel port can provide a starting point, but in many cases you must completely recode the source files. The simplest approach is to use the main functions defined in the PID code and rewrite the underlying functionality.

For example, the Angel PID port controls the device through function pointers defined between devclnt.h and devdriv.h. The main controlling functions are:

These are discussed in more detail in the following sections.

To implement a device driver you must:

Your device driver must be able to handle messages that are longer than 256 bytes in order to handle memory write messages. The actual length of memory write messages is determined by your Angel port. Refer to Download for more information.


Raw device drivers that are purely interrupt driven must fit in with the interrupt scheme described Example of Angel processing: a simple IRQ.


This function is defined in devclnt.h. It is implemented in a manner similar to the UNIX ioctl() call. It controls the device by passing in a set of standard control values that are defined in devices.h. Examples of the controls available to this function are:


Device initialization. This provides device-specific initialization at the start of a session.


Device Reset. This provides device re-initialization to set the device into a known operational state ready to accept input from the host at the default setup.


Receive mode select. This sets the device into and out of receive mode.


Set Device operational parameters. This sets the device parameters at initialization. It is also used if the host needs to re-negotiate the parameters, for example if the baud rate changes.


This control disables packet delivery when required, while still allowing the device to read data:


Packet buffers not requested. Writing to the ring buffer is allowed.


Normal operation.


deliver n good packets, then behave as RX_PACKET_FLOW(0).

Transmit Control (ControlTx)

When in operation, Angel defaults to the receive active state in order to enable quick response to host messages. This function controls the transmit channel of the serial driver, switching it on or off depending on the flag status set up in the calling routine.

Receive Control (ControlRx)

This function is similar to ControlTx. It controls the receive channel.

Transmit Kick Start (KickStartFn)

Transmission must be initiated by this function because Angel generally operates in receive active mode. The Angel packet construction code sets up the bytes to be transmitted for a message to the host in a transmit buffer and calls the KickStartFn() function to initiate the transfer. The KickStartFn() takes the first character from the transmit buffer and passes it to the serial Tx register. This causes a Tx interrupt from which the interrupt handler passes the remainder of the buffer as each character is transmitted.

Interrupt handlers

The interrupt handlers are generic for each peripheral. In the case of the PID board the interrupt handler controls interrupts from each serial driver Tx and Rx in addition to the parallel reads.

The interrupt handler determines the source of the interrupt:

  • for the Tx case, it passes bytes from the internal Tx buffer to the Serial Tx FIFO as long as there is space in the FIFO.

  • for the Rx case, it passes the byte received at the Rx FIFO into the internal Rx buffer, ready for Angel to unpack the message when the transfer is complete.

  • for the parallel case, the parallel port is polled to pass the received data into the memory location requested.

Refer to Example of Angel processing: a simple IRQ for more information on how Angel handles interrupts. Refer to Angel task management for information on how Angel serializes communications tasks.


Other system drivers (Ethernet/DCC) might not need the full operation functions described above. They might need only a pure Rx/Tx control.

Polled devices

The registered read and write poll functions are called by the Angel_DeviceYield() function. Angel ensures this function is called whenever communication with the host is required. On each call, the device poll handler ensures that the device is serviced.

For a full Angel system, a hardware timer must be available for polled devices to work because the timer interrupt is used to gain control of the processor and call Angel_DeviceYield(). This call must be inserted at the end of the timer interrupt handler for the port, because the timer itself is part of the port. For example:

 /* See if it is time to call Angel_Yield yet */
if (++call_yield_count >= call_yield_every_n_irqs)
	NULL, empty_stack, &Angel_GlobalRegBlock[RB_Interrupted]);

The value call_yield_every_n_irqs must be calculated such that Angel_Yield() is called approximately every 0.2 seconds.

Copyright © 1997, 1998 ARM Limited. All rights reserved.ARM DUI 0040D