Programming Tips

This wiki describes an example coding of the freertos_posix driver for the dsPic33 development board. Please refer to the actual coding used from here.

Memory Map for dsPIC33FJ256GP506
[1] Each address is 16-bit wide. Every two addresses correspond to a 24-bit instruction. Each even address contains 2 valid bytes; each odd address contains 1 valid byte plus 1 fathom byte.

Data Location

 * 1) N must be a power of two, with a minimum value of 2.


typedef unsigned char          __u8; typedef char                   __s8; typedef unsigned int           __u16; typedef int                    __s16; typedef unsigned long          __u32; typedef long                   __s32; typedef unsigned long long     __u64; typedef long long              __s64; //to be used in  typedef unsigned long           time_t; /** Interrupt Request */ #define _IRQ                   __attribute__((__interrupt__)) /** TRAP IRQ for saving program counter: declare __u16 StkAddrLo, StkAddrHi in trap.c (order matters) */ #define _TRAP_IRQ              __attribute__((__interrupt__(__preprologue__( \ "mov #_StkAddrHi,w1\n\tpop [w1--]\n\tpop [w1++]\n\tpush [w1--]\n\tpush [w1++]")))) /** IO Stub Functions are placed in .libc section so that the standard libraries can access these functions using short jumps. */ #define _LIBC                   __attribute__((section(".libc"))) /** FAST RAM */ #define _DMA                   __attribute__((space(dma),aligned(256)))
 * The following maps the basic data types:
 * The following macros are the platform-dependent

Custom Linker Script to Maximize Space for Constant Data

 * Constant data declared using keyword const will be stored in the .const section in the flash memory.
 * Normally, during compilation, the linker will assign these data after the program code (.text section).
 * Since .const is accessed by auto-psv function, to maximize the space for constant data (32kb), the .const section needs to be aligned at 0x80000 boundary.
 * This requires the following change in linker script:

__CONST_BASE = 0x8000; .text __CODE_BASE : { 	*(.reset); *(.handle); *(.libc) *(.libm) *(.libdsp); /* keep together in this order */ *(.lib*); /* *(.text);		deleted to maximize space for const data */ } >program .const __CONST_BASE : { 	*(.const); } >program

-mlarge-code -mlarge-data /usr/pic30-elf/lib//libc-elf.a(fflush.eo)(.libc+0x3c): In function '.LM11': : Link Error: relocation truncated to fit: PC RELATIVE BRANCH _write /usr/pic30-elf/lib//libc-elf.a(fclose.eo)(.libc+0x42): In function '.LM18': : Link Error: relocation truncated to fit: PC RELATIVE BRANCH _close int _LIBC open(const char *pathname, int flags){ ... }   int _LIBC close(int fd){ ... }   int _LIBC write(int fd, void* buf, int count) { ... }   int _LIBC read(int fd, void* buf, int count) { ... }   int _LIBC ioctl(int fd, int request, void* argp) { ... }   int _LIBC lseek(int fd, int offset, int whence) { ... }
 * If your program is large, after this change in linker script, function calls may involve large jump in the memory map (>32kB). As a result, you may need to enable the large code and large memory model during compilation. In such case, use the following options in your build path:
 * Meanwhile, functions that are defined in the standard C libraries, but are replaced with your own implementations (e.g. I/O stubs: open, read, write, lseek, ioctl etc.) may have the following linker error:
 * To resolve the problem, you need to place the functions in the .libc section rather than in the .text section, like this:

Clock Speed

 * System clock source can be provided by:
 * 1) Primary oscillator (OSC1, OSC2)
 * 2) Secondary oscillator (SOSCO and SOSCI) with 32kHz crystal
 * 3) Internal Fast RC (FRC) oscillator at 7.37MHz (7372800Hz)
 * 4) Low-Power RC (LPRC) oscillator (Watchdog Timer) at 512 kHz.
 * These clock sources can be incorporated with interal Phase-locked-loop (PLL) x4, x8 or x16 to yield the osciallator frequrence FOSC
 * The system clock is divided by 4 to yield the internal instruction cycle clock, FCY=FOSC/4

System Clock
void prvSetupTimerInterrupt (void) {    T1CON = 0; TMR1 = 0; PR1 = 50000; //============================================================    IPC0bits.T1IP = configKERNEL_INTERRUPT_PRIORITY; IFS0bits.T1IF = 0; IEC0bits.T1IE = 1; //============================================================    T1CONbits.TCKPS0 = 1; T1CONbits.TCKPS1 = 0; T1CONbits.TON = 1; }  //********************************************************************   void _IRQ _T1Interrupt (void) {    IFS0bits.T1IF = 0; vTaskIncrementTick; portYIELD; }
 * Each timer is 16-bit (i.e. counting from 0 to 65535).
 * Prescale is the ratio between timer counts and system clock counts. Prescales of 1:1, 1:8, 1:64 and 1:256 are available.
 * Let required time for ticking be PERIOD.
 * Number of instruction cycles during PERIOD = PERIOD*FCY cycles
 * Using a prescale of 1:x, the timer period count register = # of cycles/x
 * e.g. PERIOD = 10ms; # of cycles = 10ms*40MHz = 400000 cycles; Using 1:8 Prescale, register setting = 400000/8 = 50000


#define IPL             ( 0x00e0 ) #define cli           SR |= IPL    //Set IPL to 7 #define sti           SR &= ~IPL   //Set IPL to 0
 * Registers are involved in Interrupts includes:
 * 1) Interrupt Flag Status (IFS0-IFS2) registers
 * 2) Interrupt Enable Control (IEC0-IEC2) registers
 * 3) Interrupt Priority Control (IPC0-IPC10) registers
 * 4) Interrupt Priority Level (IPL) register
 * 5) Global Interrupt Control (INTCON1, INTCON2) registers
 * 6) Interrupt vector (INTTREG) register
 * User may assign priority level 0-7 to a specific interrupt using IPC. Setting priority to 0 disable a specific interrupt. Level 7 interrupt has the highest priority.
 * Current priority level is stored in bit<7:5> of Status Register (SR). Setting Interrupt Priority Level (IPL) to 7 disables all interrupts (except traps).
 * sti and cli can be defined to enable and disable global interrupts for time critical functions:

POSIX System Call and Drivers

 * POSIX System Calls (open, close, read, write, lseek) are used to access hardware devices related to data stream.
 * The file descriptor return by open for these devices are statically assigned at compile time.

UART

 * Serves as the default communication channel for STDIN, STDOUT and STDERR.
 * Implementation of this driver allows transparent operation of printf in standard C library.

I2C
Pull-up resistor (min) = (Vdd-0.4)/0.003 ...... [See section 21.8 in Family reference manual]
 * A number of I2C devices can be added using this driver (e.g. I2C DAC, I2C EEPROM, etc)
 * Two lines are devoted for the serial communication. SCL for clock, SDA for data.
 * Standard communication speed includes
 * 1) Standard speed mode: 100kHz
 * 2) Fast speed mode: 400kHz
 * 3) High speed mode: 3.4MHz
 * Pull-up resistors are required for both SCL and SDA. Minimum pull-up resistance is given by:
 * 2.2Kohm is typical for standard speed mode.
 * After initiating a start/stop/restart bit, add a small delay (e.g. no operation) before polling the corresponding control bit (hardware controlled).
 * After sending a byte and receiving an acknowledgment from the slave device, ensure to change to idle state.

ADC

 * 12-bit ADC: (Max 18 Channels)
 * ADC uses DMA to buffer the adc data.
 * A maximum of 500kps of sampling rate when using auto sampling mode.

Simple PWM (Output Compare Module)
fPWM = fCY/(Prescale*10rlog(2))
 * The PWM module consists of 8 channels using the output compare module of dsPic.
 * These channels are locate at pin 46 (OC1), 49 (OC2), 50 (OC3), 51 (OC4), 52 (OC5), 53 (OC6), 54 (OC7), 55 (OC8). These pins are shared with port D.
 * The range of PWM freqeuencies obtainable is 2Hz to 15MHz (See Figure 6.3). Suggested range of operation is 2Hz to 120kHz. The relationship between resolution r and PWM frequency fPWM is given by:

run-time self-programming flash
Some chips allow programs to write to flash memory (program memory); this process is called RTSP (run-time self-programming).

Flash-emulated EEPROM
 * Using built-in functions __builtin_tblpage, __builtin_tbloffset to set special-purpose registers to access flash memory
 * Using assembly code to read and write flash memory.

"Trying to get my head around RTSP"

The KeaDrone project has some code for reading and writing flash on a PIC24F chip: 

DSP Library

 * Not POSIX compliant
 * Library functions in  include the following categories:
 * 1) Vector
 * 2) Window
 * 3) Matrix
 * 4) Filtering
 * 5) Transform
 * 6) Control

Data Types

 * Signed Fractional Value (1.15 data format)
 * Inputs and outputs of the dsp functions adopt 1.15 data format, which consumes 16 bits to represent values between -1 to 1-2-15 inclusive.
 * Bit<15> is a signed bit, positive = 0, negative = 1.
 * Bit<14:0> are the exponent bits e.
 * Positive value = 1 - 2-15*(32768 - e)
 * Negative value = 0 - 2-15*(32768 - e)
 * 40-bit Accumulator operations (9.31 data format)
 * The dsp functions use the 40 bits accumalators during arithmatic calculations.
 * Bit<39:31> are signed bits, positive = 0x000, negative = 0x1FF.
 * Bit<30:0> are exponent bits.
 * IEEE Floating Point Values
 * Fractional values can be converted to Floating point values using: fo = Fract2Float(fr); for fr = [-1, 1-2-15]
 * Floating point values can be converted to Fractional values using: fr = Float2Fract(fo); or fr = Q15(fo); for fo = [-1, 1-2-15]
 * Float2Fract is same as Q15, except having saturation control. When +ve >= 1, answer = 215-1 = 32767 (0x7FFF). When -ve < -1, answer = -215 = -32767 (0x8000)

Fast Fourier Transform

 * to be added