As well explained in Bill document the different tasks are executed at appropriate rate to have a well balanced code, allowing a lot of computations also with processors smaller then dsPIC33F. Increasing CPU clock frequency it is possible to get more power but, any case, it is a good programming technique to wonder accurately about the real needs. I've added the I2C communication with dsNAV, sharing the same bus with magnetometer, the communication is executed at the same 40Hz rate, after the robot attitude is computed an DCM is ready with new values. This 25ms period is a good compromise between processor load and refresh rate for navigation board.

update on 05-03-2013

IMU

UDB4 GPS Magnetometer

Through the IMU all the navigation peripherals are connected to the HLS, so the communications of this board have to be well designed to not interfere with all interrupt-driven lino-UDB4 code.

UART1 is dedicated to talk with GPS @ 19200bps in binary mode. This is to have minimum latency on readings, otherwise, even if the update is as slow as 1Hz rate, it can replays also with some seconds delay.

UART2 is used for telemetry @ 57600bps for both test or real work.

All functions which name starts with "GO_" are my personal additions to the original MatrixPilot software, Vers. 3.3 R.1880 - Dec.26th 2012

I2C 1 module is dedicated to 24LC256 EEPROM installed on UDB4 board (not used in my code).

I2C 2 is used for communication with magnetometer and dsNav.

All the communication callback functions are triggered by peripherals interrupt, to avoid slowing down the program. The I2C bus, because it is shared among multiple devices, uses also a multi buffer mode to allow different devices to have their own EEPROM-like exchange sequence.
The read and write I2C functions are a very clever usage of pointers and Function Pointers. The different transmit or receive buffers are passed as reference and also the function to call next in case of success is referenced in the call, allowing an easy way of creating a Finite State Machine.


Also serial communication is an FSM realized with function pointers, where everything starts from UART module interrupt, triggered both by a byte to send or receive or by setting interrupt flag with software (example).
This is another very interesting embedded programming style I learned from William Premerlani and MatrixPilot software staff on UDB developers Google group:
The main code is extremely simple, only an infinite loop. Everything is ISRs driven. Even critical functions not directly related to hardware peripherals are triggered setting by software the relative interrupt flag.
The different I2C bus voltage between Arduino and dsPIC33, fits perfectly with my needs. Arduino talks with 5V devices and dsPIC33 with 3.3V peripherals only, obtaining two separate busses with no voltage level translators needed.
A dedicated software module has been also written to manage such kind of software events. In this way it is possible to use the powerful priority options of dsPIC33 to share processor with both critical and non critical procedures.

S : (r) Ref. speed and heading setting (mm/s and degrees)
T : (w) Time details send (Year, Month, Day, Hour, Min, Sec)
G: (w) GPS service params request and receive (Sats., Quality)
b : (w) Speed, current and position details send (mm/s, mA, m)
K : (w) GPS and IMU details send (GPS and DCM)

 

After the communication successfully ends e very simple command parser starts executing the requested functions.
'w' = data written (IMU -> HLS)
'r' = data read (IMU <- HLS)

After learning this technique to realize a Finite State Machine, it was even easier to insert also in this environment my communication protocol without disturbing other procedures. Instead of using switch/case classic procedure I've added my own conditional compilation addition, that starts all the "GO_" series of communication procedures.
The buffers used for TX and RX are realized with struct and union C options to simplify the conversion from different length variables (int, char, long and especially float) to the char register used by both serial and I2C communication. It is possible to point to the correct memory address to send only one byte at a time and then rebuild the same kind of variable with a mirror conversion on the receiving side.