Programming Tips

From OpenCircuits
Jump to: navigation, search

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.

Contents

Memory

Memory Map for dsPIC33FJ256GP506

Type Start Address End Address Size
Flash 0x000000 0x02ABFF 171K[1]
+--Flash: Reset Vector 0x000000 0x000003 4
+--Flash: Interrupt Vector Table 0x000004 0x0000FF 252
+--Flash: Alternate Vector Table 0x000104 0x0001FF 252
+--Flash: User Program 0x000200 0x02ABFF 170.5K
Programming Executive 0x800000 0x800FFF 4K[1]
Config Registers 0xF80000 0xF80017 24
Device ID (0xF5) 0xFF0000 0xFF0003 4

[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

Type Description Example
_XBSS(N) [1] RAM Data in X-memory, aligned at N, no initilization int _XBSS(32) xbuf[16];
_XDATA(N) [1] RAM Data in X-memory, aligned at N, with initialization int _XDATA(32) xbuf[] = {1, 2, 3, 4, 5};
_YBSS(N) [1] RAM Data in Y-memory, aligned at N, no initialization int _YBSS(32) ybuf[16];
_YDATA(N) [1] RAM Data in Y-memory, aligned at N, with initialization int _YDATA(32) ybuf[16] = {1, 2, 3, 4, 5};
__attribute__((space(dma)) RAM Data in DMA int __attribute__((space(dma)) data[128];
__attribute__((space(const))) Flash ROM data, constant, accessed by normal C
statements, but 32K max.
int i __attribute__((space(const))) = 10;
__attribute__((space(prog))) Flash ROM data, read/write by program space visibility
window (psv)
int i __attribute__((space(prog)));
__attribute__((space(auto_psv))) Flash ROM data, read by normal C statements, write
by accessing psv
int i __attribute__((space(auto_psv)));
__attribute__((space(psv))) Flash ROM data, read/write by (psv) int i __attribute__((space(psv)));
_PERSISTENT RAM Data, data remain after reset int _PERSISTENT var1, var2;
_NEAR RAM Data at near section int _NEAR var1, var2;
__attribute__((__interrupt__)) Interrupt service rountine void __attribute__((__interrupt__)) _INT0Interrupt(void);
  1. N must be a power of two, with a minimum value of 2.


<asm/types.h>

  • The following maps the basic data types:
 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 <time.h>
 typedef unsigned long           time_t;
  • The following macros are the platform-dependent
 /** 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)))


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
  • 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:
   -mlarge-code -mlarge-data
  • 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:
   /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 
  • To resolve the problem, you need to place the functions in the .libc section rather than in the .text section, like this:
   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) { ... }


System Setup

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

  • 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
  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();
  }


<asm/system.h>

  • 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:
 #define IPL              ( 0x00e0 )
 #define cli()            SR |= IPL    //Set IPL to 7
 #define sti()            SR &= ~IPL   //Set IPL to 0


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

  • 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:
    Pull-up resistor (min) = (Vdd-0.4)/0.003  ......  [See section 21.8 in Family reference manual]
  • 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)

  • 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:
        fPWM = fCY/(Prescale*10rlog(2))
Relationship of Resolution and PWM Frequency
Resolution (bit) Prescale=1 Prescale=8 Prescale=64 Prescale=256
1 15,000,000 1,875,000 234,375 58,594
2 7,500,000 937,500 117,188 29,297
3 3,750,000 468,750 58,594 14,648
4 1,875,000 234,375 29,297 7,324
5 937,500 117,188 14,648 3,662
6 468,750 58,594 7,324 1,831
7 234,375 29,297 3,662 916
8 117,188 14,648 1,831 458
9 58,594 7,324 916 229
10 29,297 3,662 458 114
11 14,648 1,831 229 57
12 7,324 916 114 29
13 3,662 458 57 14
14 1,831 229 29 7
15 916 114 14 4
16 458 57 7 2


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: [1]

DSP Library

  • Not POSIX compliant
  • Library functions in <dsp.h> 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
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox