DsPIC30F 5011 Development Board
Contents
- 1 Introduction
- 2 Programming Methods
- 3 Circuit Design and PCB
- 4 Development Environment
- 5 Software Architecture
- 6 Programming Tips
- 7 Bootloader Development
- 8 USB-RS232 Interface
- 9 Programming the Device
- 10 To Do List
Introduction
Features of dsPIC30F5011
- 2.5 to 5V
- Up to 30MIPs
- High current/sink source I/O pins: 25mA
- DSP Instruction Set
- Dual programming techniques: ICSP and RTSP
- UART: up to 2 modules
- I2C: up to 1Mbps
- 10-bit A/D, 1.1 Msps
- 12-bit A/D, 200 ksps
- 66Kb flash, 4Kb RAM, 1Kb EEPROM
- No DAC
Web Page
Forum
- Microchip: Official forum by Microchip
- MPLAB ICD 2: Subforum on ICD 2 programmer
- MPLAB IDE: Subforum on IDE
- MPLAB C30 Compiler, ASM30, Link30 forum: Subforum on C compiler. Refer to MPLAB C30 C Compiler User's Guide Chapter 3
- dsPIC30F Topics: Subformum on dsPIC30F
- HI-TECH Software Forum: Discussion on dsPICC, a C compiler developed by HI-TECH
- PICList: Discussion on older PIC systems (not dsPIC)
- PicKit: Discussion on PICkit/PICkit 2 programmers
References
- dsPIC30F
- Family Overview
- Family Reference Manual: Contains detailed descriptions on dsPIC30F register definitions and example codes
- 5011 Data Sheet
- Flash Programming Specification
- Programmer Reference Manual
- ICD2 Programmer
- MPLAB
- C30 Compiler
- MPLAB C30 C Compiler User's Guide: Contains commands for using pic30-elf-gcc
- 16-bit Language Tools Libraries: Contains summaries and examples of using DSP libraries, standard C libraries and device libraries
- MPLAB ASM30, MPLAB LINK30 and Utilities User's Guide
- dsPIC30F Language Tools Quick Reference Card
Programming Methods
- There are 2 programming methods: In-Circuit Serial Programming (ICSP) and Run-Time Self-Programming (RTSP)
- ICSP allows the devices to be programmed after being placed in a circuit board.
- RTSP allows the devices to be programmed when an embedded program is already in operation.
ICSP: External Programmer (ICD2)
- Two types of ICSP are available: ICSP and Enhanced ICSP. Both of them require setting MCLR# to VIHH (9V – 13.25V).
- Standard ICSP
- Use external programmer (e.g. MPLAB® ICD 2, MPLAB® PM3 or PRO MATE® II) only.
- Required low-level programming to erase, program and verify the chip.
- Slower, because codes are serially executed.
- Program memory can be erased using Normal-Voltage (4.5 – 5.5V) or Low-Voltage (2.5V – 4.5V).
- Enhanced ICSP
- Use external programmer and Programming Executive (PE).
- PE is stored in the on-chip memory.
- PE allows faster programming.
- PE can be downloaded to the chip by external programmer using the standard ICSP method.
- PE contains a small command set to erase, program and verify the chip, avoiding the need of low-level programming.
Hardware Interface
Pin Label | Function | Pin Number |
---|---|---|
MCLR# | Programming Enable | 7 |
VDD | Power Supply | 10, 26, 38, 57 |
VSS | Ground | 9, 25, 41, 56 |
PGC | Serial Clock | 17 |
PGD | Serial Data | 18 |
Product Name | Interface with PC | Interface with Device | Price (US) | Postage (US) | Total (US) |
---|---|---|---|---|---|
MPLAB® ICD 2 | USB or RS232 | 6-PIN RJ-12 connector | $159.99 | - | - |
Full Speed USB Microchip ICD2 Debugger and Programmer |
USB | 6-PIN ICSP connector 6-PIN RJ-12 connector |
$72.00 | $12.00 | $84.00 |
Mini Microchip Compatible ICD2 Debugger and Programmer |
RS232 | 6-PIN ICSP connector 6-PIN RJ-12 connector |
$45.00 | $10.00 | $55.00 |
ICDX30 | RS232 | 6-pin RJ-11 | $51.00 | $47.46 | $98.46 |
Clone Microchip ICD2 | USB | 6-pin flat cables | $30.00 | $12.00 | $42.00 |
Source | Schematic | PIC16F877A Bootloader |
---|---|---|
Patrick Touzet | Yes | HEX |
Nebadje | Yes | Zip |
Software Interface
- The program can be written and compiled in an Integrated Development Environment (IDE) using either Assembly or C. The complied codes are then loaded to the device through the external programmer.
Product Name | Features | OS | Price (US$) |
---|---|---|---|
MPLAB® IDE | Assembler Only | Windows | Free |
MPLAB® C30 | Assembler and C-Compiler | Windows | $895.00 (Free student version1) |
Piklab 0.12.0 | Assembler and C-Compiler | Linux | Free2 |
- Full-featured for the first 60 days. After 60 days only optimization level 1 can be enabled in the compiler. The compiler will continue to function after 60 days, but code size may increase.
- The current version supports external programmer ICD 2, but not yet tested.
RTSP: COM Port (Bootloader)
- RTSP works in normal voltage (^MCLR no need to raise to VIHH).
- No literature has mentioned the incorporation of Programming Executive (PE). Presumably, since Enhanced ICSP needs to set MCLR# to VIHH, RTSP cannot use PE.
- Refer to bootloader section.
Circuit Design and PCB
IC Requirements
Part No. | Description | Min Temp | Max Temp | Min Volt | Max Volt | Typ Cur | Max Cur |
---|---|---|---|---|---|---|---|
dsPIC30F5011-30I/PT | uP | -40oC | 85oC | 2.5V [1] | 5.5V | 250mA | |
MAX3232ESE | RS232 driver | -40oC | 85oC | 3.0V | 5.5V | 0.3mA | 1.0mA |
ADM483E ANZ | RS485 driver | -40oC | 85oC | 4.5V | 5.5V | 0.036mA | |
DAC6574DGS | 10-bit Quad-DAC I2C | -40oC | 105oC | 2.7V | 5.5V | 0.6mA | 0.9mA |
74HC14D | Quad-Schmitt Trigger | -40oC | 125oC | 2.0V | 6.0V | 50mA | |
Overall | -40oC | 85oC | 4.5V | 5.5V | <310mA [2] |
- Minimum voltage measured is 3.3V (with 2 LEDs blinking) running at 30MHz.
- Measured current at 5V is 180mA (with 2 LEDs blinking only)
Module Board
- Functions
- Primary communication with other module boards via RS232 over short distance.
- Secondary communication with benchtop via RS458 over longer distance.
- Digital control I/O for 1 laser (e.g. on/off, detect temp overheat, current alarm)
- Analog input for data acquisation on power, current and temperature
- Analog output for power and current control
Digital Input | Digital Output | Analog Input | Analog Output |
---|---|---|---|
1. ICSP | 1. LED 2. Bi-color LED 3. RS232 4. RS458 5. Case temp overheat 6. Laser on/off 1,2 7. Interlock 8. Digital ctrl 9. Current 0,1 alarm |
1. Case temp 2. pow 0,1 3. cur0 4. temp0 |
1. 10-bit DAC |
Benchtop
- Functions
- Primary communciation with module boards via RS485
- Secondary communication with other benchtops via RS232
- Digital I/O control for 2 lasers
- Analog inputs on power, current and temperature
- Analog outputs for power and current control
- LCD display and rotary key for user input
Digital Input | Digital Output | Analog Input | Analog Output |
---|---|---|---|
1. ICSP 2. Rotary Key 3. Push Buttons |
1. LED 2. RS232 3. RS458 4.LCD display 5. Buzzer 6. Digital Ctrl 0,1 |
1. Case temp 2. CurrentDetect 0,1 3. PowerDetect 0,1,2,3 4. TempDetect |
1. 10-bit DAC (PowerCurrentCtrl 0,1) |
Development Environment
Windows
- C-Compiler, Assembler and Linker are under GNU license.
- MPLAB C30 C Compiler (*.c -> *.s)
- MPLAB ASM30 Assembler (*.s -> *.o)
- MPLAB LINK30 Linker (*.o -> *.bin)
- PA optimizer, simulator, runtime libraries, header files, include files, and linker scripts are not covered by GNU. Reference is here.
- Microchip has integrated ASM30, LINK30, assembly header files, linker scripts in MPLAB IDE, which is free for download.
- MPLAB C30 costs US$895. A 60-day free student version is also available. After 60-days, the optimizer is automatically disabled, while other tools can still function properly. Refer to Table 2.4.
- C-libraries contained in C30 includes (Refer to 16-Bit Language Tools Libraries from Microchip).
Library | Directory (\\Microchip\MPLAB C30) |
Major functions |
---|---|---|
DSP Library (e.g. libdsp-coff.a) |
\lib \src\dsp \support\h |
Vector, Matrix, Filter, etc. |
16-Bit Peripheral Libraries (e.g. libp30F5011-coff.a) |
\lib \src\peripheral \support\h |
ADC12, IOPort, UART, I2C, etc. |
Standard C Libraries (e.g. libc-coff.a, libm-coff.a, libpic-coff.a) |
\lib \src\libm \include |
stdio.h, time.h, float.h, math.h, |
MPLAB C30 Built-in Functions | none | _buildin_addab, _buildin_add, _buildinmpy, etc |
Linux
- C Compiler, Assembler and Linker are under GNU license.
- The code can be downloaded from Microchip at here.
- Current MPLAB ASM30 Assembler: v2.04
- Current MPLAB C30 Compiler: v2.04
- John Steele Scott has made templates that can be readily used by Debian-based systems. Someone at http://noel.feld.cvut.cz/dspic/ has done the necessary conversion to *.deb already.
- Download pic30-1.32-debian.tar.bz2 for Template v1.32. (For v2.01, please goto pic30-debian-2.01.tar.bz2).
- Download pic30-binutils_1.32-1_i386.deb for the assember.
- Download pic30-gcc_1.32-1_i386.deb for the compiler.
- Important Note: Only the compiler is free. The header files and library is owned by Microchip.
- Thomas Sailer suggested to download the Student version of C30 compiler and then build the libraries without source code. A package template for Fedora system is available here.
- Instructions for filling the upstream direction is available here.
- Alteratively, Stephan Walter has started a project to develop C Runtime Library for dsPIC.
- Current libraries in version 0.1.1 include: assert.h, cdefs.h, ctype.h, errno.h, inttypes.h, stdint.h, stdio.h, stdlib.h, string.h
- Burning Program Codes to Target Board
- Use 'dspicprg and dspicdmp' utilities developed by Homer Reid to burn hex code (*.hex) to devices. See Reference here. Through serial port only?
- Use Piklab IDE. Details on file format not known.
- Use MPLAB IDE to burn hex code (*.hex) to devices.
Code Optimization
- Code Optimization under GNU license supports O0 and O1 only.
- MPLAB C-Compiler supports O0, O1, O2, Os and O3. The Student version will disable O2, Os, and O3 after 60 days.
- Below is a comparsion between different optimization levels for the project including drivers for 2 projects.
Optimization | Description | Project 1 Code Size (byte) |
Project 1 Data Usage (byte) |
Project 2 Code Size (byte) |
Project 2 Data Usage (byte) |
---|---|---|---|---|---|
O0 | No optimization Fastest Compilation |
6222 (9%) | 178 (4%) | 26,037 (38%) | 710 (17%) |
O1 | Optimize Tries to reduce code size and execution time. |
4473 (6%) | 178 (4%) | 22,290 (32%) | 710 (17%) |
O2 | Optimize even more Performs nearly all supported optimizations that do not involve a space-speed trade-off. Increases both compilation time and the performance of the generated code. |
4422 (6%) | 178 (4%) | 21,993 (32%) | 710 (17%) |
O3 | Optimize yet more. O3 turns on all optimizations specified by O2 and also turns on the inline-functions option. |
4485 (6%) | 178 (4%) | 22,176 (32%) | 710 (17%) |
Os | Optimize for size. Os enables all O2 optimizations that do not typically increase code size. It also performs further optimizations designed to reduce code size. |
4356 (6%) | 178 (4%) | 21,885 (32%) | 710 (17%) |
Software Architecture
+----------+-----------+---------+---------+ | local | remote | | | +----------+-----------+ host | UI | | data access | channel | | | (DI,DO,AI,AO) | | | +----------------------+---------+---------+ | Application | | | +------------------------------------------+ | Applications Model | | +--------------+-----------+ | | | GUI | CLib | | | | +------+-----------+-------+ | | | Operating System | +-------+-------+--------------------------+ | Drivers | +------------------------------------------+ | Hardware | +------------------------------------------+
- Currently, operating system is based on linlike8. The possibility of using other OS (e.g. FreeRTOS) will be explored later.
- Software Drivers are to be developed to allow users at Application Level to use the hardware (e.g. ADC, DAC, UART, EEPROM) through the OS.
- The interface between the drivers and the OS should be compliant with POSIX standard for Linux (e.g. open(), write(), read(), ioctl() etc).
Programming Tips
Memory Map for 5011
16-bit <--------------------> +--------------------+ 0x000000
| Flash |
| (22K x 16 bits) |
+--------------------+ 0x00B000
| Reserved |
+--------------------+ 0x7FFC00
| EEPROM |
| (1K x 8 bits) |
+--------------------+ 0x800000
| Programming |
| Executive |
+--------------------+ 0x8005C0
| Unit ID |
+--------------------+ 0x800600
| Reserved |
+--------------------+ 0xF80000
| Config Registers |
+--------------------+ 0xF80010
| Reserved |
+--------------------+ 0xFF0000
| Device ID (0x0080) |
+--------------------+ 0xFF0004
| Reserved |
+--------------------+ 0xFFFFFE
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 initilization | int _XDATA(32) xbuf[] = {1, 2, 3, 4, 5}; |
_YBSS(N) [1] | RAM Data in Y-memory, aligned at N, no initilization | int _YBSS(32) ybuf[16]; |
_YDATA(N) [1] | RAM Data in Y-memory, aligned at N, with initilization | int _YDATA(32) ybuf[16] = {1, 2, 3, 4, 5}; |
__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))); |
_EEDATA(N) [1] | ROM Data in EEPROM, aligned at N, read/write with psv | int _EEDATA(2) table[]={0, 1, 2, 3, 5, 8}; |
_PERSISTENT | RAM Data, data remain after reset | int _PERSISTENT var1, var2; |
_NEAR | RAM Data at near section | int _NEAR var1, var2; |
_ISR | Interrupt service rountine | void _ISR _INT0Interrupt(void); |
_ISRFAST | Fast interrupt service rountine | void _ISRFAST _T0Interrupt(void); |
- N must be a power of two, with a minimum value of 2.
Configuration Bits
- System clock source can be provided by:
- Primary oscillator (OSC1, OSC2)
- Secondary oscillator (SOSCO and SOSCI) with 32kHz crystal
- Internal Fast RC (FRC) oscillator at 7.37MHz (7372800Hz)
- 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
- FRC with PLLx16 is used to achieve FCY=29.49MHz (29491200Hz or 30MIPS)
//The code (MACRO) below is to be placed at the top of program (before main) _FOSC(CSW_FSCM_OFF & FRC_PLL16); _FWDT(WDT_OFF); //Turn off Watchdog Timer _FBORPOR(PBOR_ON & BORV_27 & MCLR_DIS & PWRT_16); _FGS(CODE_PROT_OFF); //Disable Code Protection
Timer
- Each timer is 16-bit (i.e. counting from 0 to 65535).
- Timer 2 and 3 can be incorporated together to form a 32-bit timer.
- Prescale is the ratio between timer counts and system clock counts. Prescales of 1:1, 1:8, 1:64 and 1:256 are available.
- Timers may be used to implement free time clock or mesaure time.
Free Time Clock
- 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*30MHz = 300000 cylces; Using 1:64 Prescale, register setting = 300000/64 = 4688
void time_init(void){ TMR1 = 0; // Clear register PR1 = 4688; // Set period //============================================================ _T1IF = 0; // Clear interrupt flag _T1IE = 1; // Enable interrupts //============================================================ T1CONbits.TCS = 0; // Use internal clock source T1CONbits.TCKPS = 2; // Prescale Select 1:64 T1CONbits.TON = 1; // Start the timer } //******************************************************************** void _ISRFAST _T1Interrupt(void){ _T1IF = 0; // Clear interrupt flag //Place user code here }
Time Measurement
- To measure the time taken for action(), use the code below:
unsigned int measure_time(void){ PR3 = 0xFFFF; // Set counter to maximum _T3IF = 0; // Clear interrupt flag _T3IE = 0; // Disable interrupt T3CONbits.TON = 1; // Start the timer, TMR3 count up TMR3 = 0; //Clear TMR3 to start count up //==================================================== //Add code here to wait for something to happen action(); //==================================================== T3CONbits.TON = 0; //Stop the timer //==================================================== return (unsigned int) TMR3/FCY; //TMR/FCY yields the actual time }
Interrupt
- Registers are involved in Interrupts includes:
- Interrupt Flag Status (IFS0-IFS2) registers
- Interrupt Enable Control (IEC0-IEC2) registers
- Interrupt Priority Control (IPC0-IPC10) registers
- Interrupt Priority Level (IPL) register
- Global Interrupt Control (INTCON1, INTCON2) registers
- 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 IPL. Setting IPL to 7 disables all interrupts (except traps). The following MACROs are defined in <p30f5011.h>:
- SET_CPU_IPL(ipl): Set IPL to ipl
- SET_AND_SAVE_CPU_IPL(save_to, ipl): Store the current IPL to save_to and then set to ipl
- RESTORE_CPU_IPL(saved_to): Restore the previously saved ipl
- sti() and cli() are defined to enable and disable global interrupts for time critical functions:
extern int SAVE_IPL; #define sti() RESTORE_CPU_IPL(SAVE_IPL) #define cli() SET_AND_SAVE_CPU_IPL(SAVE_IPL, 7) //============================================================ char adc_ioctl(unsigned char request, unsigned char* argp){ //... cli(); //Disable global interrupt for(;ch<=argp[0];ch++) adc_add_ch(argp[ch]); //Add adc channels sti(); //Enable global interrupt //... return 0; }
UART
- 5011 provides two UART channels UxART, for x=1, 2.
- UxMODE, UxSTA, UxBRG are registers used to set the mode, indicate the status, and set the baud rate respectively.
- For UART communications compatiable with RS232 standard, an external driver (e.g. MAX3232ESE) is needed.
- For UART communications compatiable with RS485 standard, an external driver (e.g. DS3695N) is needed.
Auto baud rate detection
- The method is provided by ingenia bootloader.
- The PC sends a ASCII character 'U' (0x55) to the target board.
- On the first rising edge of the start bit, the target board starts the timer.
- At the fifth rising edge, the timer is stopped, let the count number be t_count.
- The measured period corresponds to 8 bits transmitted at a baud rate uxbrg.
_ _ _ _ _ _ _|S|_|1|_|1|_|1|_|1|_|S|_ (S = Start Bit) <---------------> Measured Time
- The relationship between uxbrg and TMR is
Measured Time (in seconds) = t_count/Fcy uxbrg = 1/(Measured Time/8) = 8*Fcy/t_count
- Since UxBRG is computed by:
UxBRG = (Fcy/(16*Baudrate)) -1 = (Fcy/(16*8*Fcy/t_count)) -1 = t_count/128 -1
- The following is the code for auto baud rate detection for U2ART:
unsigned int uart2_autobaud(void){ U2MODEbits.ABAUD = 1; //Enable Autobaud detect from U2RX (from IC2 if 0) U2MODEbits.UARTEN = 1; //U2ART enable //Timer 3 Config========================================================== PR3 = 0xFFFF; // Set counter to maximum _T3IF = 0; // Clear interrupt flag _T3IE = 0; // Disable interrupt T3CONbits.TON = 1; // Start the timer, TMR3 count up //Input Capture Config==================================================== IC2CONbits.ICM = 3; //Detect rising _IC2IF = 0; //Clear interrupt flag _IC2IE = 0; //Disable interrupt //Start Auto baud detection=============================================== unsigned int i=0; cli(); //Disable Global Interrupt while(!_IC2IF); //1st rising edge detected TMR3 = 0; //Clear TMR3 to start count up _IC2IF = 0; //Clear interrupt flag while(!_IC2IF); //2nd rising edge detected _IC2IF = 0; //Clear interrupt flag while(!_IC2IF); //3rd rising edge detected _IC2IF = 0; //Clear interrupt flag while(!_IC2IF); //4th rising edge detected _IC2IF = 0; //Clear interrupt flag while(!_IC2IF); //5th rising edge detected _IC2IF = 0; //Clear interrupt flag T3CONbits.TON = 0; //Stop the timer sti(); //Enable Global Interrupt //Compute value for BRG register========================================== unsigned int time; time = ((TMR3+0x40)>>7)-1; //+0x40 for rounding //======================================================================== return time; }
- For 30MIP, tested speeds of transmission include 9600bps, 19200bps, 28800bps, 38400bps and 57600bps.
Initialize UART
void uart2_init(void){ //================================================================= // Configure Baud rate // +-- Default Baud rate = 19.2 kbps // +-- U2BRG = 30e6 / (16 * 19200) - 1 = 97 unsigned int u2brg = 97; #if(AUTO_BAUD_DECT>0) u2brg = uart2_autobaud(); #endif U2BRG = u2brg; //================================================================= // Disable U2ART U2MODEbits.UARTEN = 0; //Disable U2ART module //================================================================= // Configure Interrupt Priority _U2RXIF = 0; //Clear Rx interrupt flags _U2TXIF = 0; //Clear Tx interrupt flags _U2RXIE = 1; //Receive interrupt: 0 disable, 1 enable _U2TXIE = 1; //Transmit interrupt: 0 disable, 1 enable //================================================================= // Configure Mode // +--Default: 8N1, no loopback, no wake in sleep mode, continue in idle mode // +--Diable autobaud detect // +--Enable U2ART module U2MODEbits.ABAUD = 0; //Disable Autobaud detect from U2RX U2MODEbits.UARTEN = 1; //U2ART enable //================================================================= // Configure Status // +--Default: TxInt when a char is transmitted, no break char // +--Default: RxInt when a char is received, no address detect, clear overflow // +--Enable Transmit U2STAbits.UTXEN = 1; //Tx enable }
Sending and Receiving Data
void _ISR _U2TXInterrupt(void){ _U2TXIF = 0; //Clear Interrupt Flag if(tx_data_ready()) U2TXREG = tx_buf[POS]; //send next byte... } void _ISR _U2RXInterrupt(void){ _U2RXIF = 0; //Clear the flag if ( U2STAbits.URXDA ){ rx_buf[POS] = (unsigned char) U2RXREG; //Read the data from buffer } }
I2C
- Two lines are devoted for the serial communication. SCL for clock, SDA for data.
- Standard communication speed includes
- Standard speed mode: 100kHz
- Fast speed mode: 400kHz
- High speed mode: 3.4MHz
- dsPIC30f5011 supports standard and fast speed modes. The maximum speed attainable is 1MHz.
- 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). For example:
StartI2C();
Nop(); //A small delay for hardware to respond
while(I2CCONbits.SEN); //Wait till Start sequence is completed
- After sending a byte and receiving an acknowledgement from the slave device, ensure to change to idle state. For example:
MasterWriteI2C(0x55);
while(I2CSTATbits.TBF); //Wait for transmit buffer to empty
while(I2CSTATbits.ACKSTAT); //Wait for slave acknowledgement
IdleI2C();
ADC
- 12-bit ADC: (Max 16 Channels)
- Allow a maximum of 2 sets of analog input multiplexer configurations, MUX A and MUX B (Normally use one only).
- A maximum of 200kps of sampling rate when using auto sampling mode.
Configuration
- Interrupt: Clear ADC interrupt flag and enable ADC interrupt. The ADC module will be set to interrupt when the specified channels are updated.
_ADIF = 0; //clear ADC interrupt flag _ADIE = 1; //enable adc interrupt
- I/O: Set the corresponding TRISBX bits (digit i/o config) to input (i.e. = 1), and set corresponding bits in ADPCFG (analog config) to zero.
_TRISB2 = 1; //Set AN2 [Case Temp] as analog input _TRISB8 = 1; //Set AN8 [Power detect 0] as analog input _TRISB9 = 1; //Set AN9 [Power detect 1] as analog input _TRISB10 = 1; //Set AN10 [Current detect 0] as analog input _TRISB11 = 1; //Set AN11 [Temp detect 0] as analog input ADPCFG = 0xF0FB; //0 => Analog, 1 => Digital
- Scanning Mode: Scan mode is used. In this mode, the Sample and Hold (S/H) is switched between the channels specified by ADCSSL (Scan select register).
ADCSSL = 0x0F04; //0 => Skip, 1 => Scan
- Reference Voltage for S/H: Only MUX A is used. By default, the negative reference voltage of the S/H is connected to VREF-.
ADCHSbits.CH0NA = 0;
- Sampling Rate: TAD refers to the time unit for the ADC clock. To configure the ADC module at 200kbps, the minimum sampling time of 1TAD = 334ns is required. ADCS<5:0> in ADCON3 register is used to set the time, which is given by:
ADCS<5:0> = 2(TAD/TCY)-1 = 2(334e-9/33.34e-9)-1 = 19
ADCON3bits.SAMC = 1; //1TAD for sampling time ADCON3bits.ADRC = 1; //Use internal ADC clock ADCON3bits.ADCS = 19; //Set TAD = 334ns
- Settings for ADC Operation: For 200kbps operation, the voltage references for the ADC voltage are connected to VREF+ and VREF-. Scan input is enabled, and the module will generate an interrupt when all selected channels have been scanned.
ADCON2bits.VCFG = 3; //External Vref+, Vref- ADCON2bits.CSCNA = 1; //Scan input ADCON2bits.SMPI = 4; //take 5 samples (one sample per channel) per interrupt
- More Settings for ADC Operation: Turn on the module, select the data output format as unsigned integer, and allow auto setting of SAMP bit (auto sampling).
ADCON1bits.ADON = 1; //Turn on module ADCON1bits.FORM = 0; //[2 fractional]; [3 siged fractional] ADCON1bits.SSRC = 7; //auto covert, using internal clock source ADCON1bits.ASAM = 1; //auto setting of SAMP bit
Storing ADC Data
- 16 registers (ADCBUF0 -ADCBUF15) are dedicated to store the ADC data between interrupts. However, the data in ADCBUFx does not necessarily correspond to the data taken for channel x. Since the lowest register will always be filled first, when some of the channels are not scanned (i.e. skipped), care must be taken. The following code checks the ADCSSL register for the current scanning channels and moves the data to the corresponding position in *adc_buf.
void _ISR _ADCInterrupt(void){ _ADIF = 0; //Clear adc interrupt //========================================================== unsigned char channel = 0; unsigned char buffer = 0; for (; channel<ADC_MAX_CH; channel++){ if(adc_ch_updated(channel)){ //Check if channel has updated adc_buf[channel] = ADC16Ptr[buffer]; //Copy data to adc_buf buffer++; } } } unsigned char adc_ch_updated(unsigned char ch){ unsigned int mask; mask = 0x0001 << ch; if(ADCSSL & mask) return 1; return 0; }
Adding and Removing Channels
- Channels may be added or removed by changing _TRISBX, ADPCFG, ADCSSL and ADCON2bits.SMPI.
void adc_add_ch(unsigned char ch){ //Enable i/o pin as input=========================================== switch(ch){ case 0: _TRISB0 = 1; break; case 1: _TRISB1 = 1; break; case 2: _TRISB2 = 1; break; case 3: _TRISB3 = 1; break; case 4: _TRISB4 = 1; break; case 5: _TRISB5 = 1; break; case 6: _TRISB6 = 1; break; case 7: _TRISB7 = 1; break; case 8: _TRISB8 = 1; break; case 9: _TRISB9 = 1; break; case 10: _TRISB10 = 1; break; case 11: _TRISB11 = 1; break; case 12: _TRISB12 = 1; break; case 13: _TRISB13 = 1; break; case 14: _TRISB14 = 1; break; default: _TRISB15 = 1; } unsigned int mask; mask = 0x0001 << ch; ADCSSL = ADCSSL | mask; ADPCFG = ~ADCSSL; ADCON2bits.SMPI++; //take one more sample per interrupt } void adc_rm_ch(unsigned char ch){ unsigned int mask; mask = 0x0001 << ch; ADPCFG = ADPCFG | mask; ADCSSL = ~ADPCFG; ADCON2bits.SMPI--; //take one less sample per interrupt }
EEPROM
- 5011 has 1024 bytes of EEPROM, readable and writable under normal voltage (5V).
- To use, declare:
unsigned char _EEDATA(2) eeData[1024]={ 0x00, 0x00, 0x00, 0x00, .... } unsigned int byte_pointer = 0;
Seek
- This function moves the pointer to the desired position before a reading/writing operation is performed.
int eeprom_lseek(int offset, unsigned char whence){ byte_pointer = offset; return byte_pointer; }
Read
- This function read count bytes from the eeprom.
int eeprom_read(unsigned char* buf, int count){ int i=0; for(; i<count && byte_pointer < 1024; i++){ readEEByte( __builtin_tblpage(eeData), __builtin_tbloffset(eeData) + byte_pointer, &buf[i]); byte_pointer++; //Update global pointer } return i; //read i bytes successful }
- readEEByte() is implemented in assembly code as follows:
.global _readEEByte _readEEByte: push TBLPAG ;w0 = base of eeData mov w0, TBLPAG ;w1 = offset for eeData in byte tblrdl.b [w1], [w2] ;w2 = pointer to user buffer pop TBLPAG return
Write
- This function write count bytes to eeprom.
int eeprom_write(unsigned char* buf, int count){ char isOddAddr = byte_pointer%2; //current address is odd char isOddByte = count%2; //number of bytes to write is odd //================================================================= unsigned int word_offset = byte_pointer>>1; //div by 2 and round down int max_write; max_write = (isOddAddr == 0 && isOddByte == 0) ? (count>>1) : (count>>1)+1; //================================================================= unsigned int word_data; //Store word to be written int byte_wr = 0; //number of bytes written, i.e buffer pointer int i = 0; //================================================================= for(; i<max_write && word_offset<512; i++, word_offset++){ if(i==0 && isOddAddr){ //First byte not used //============================================save first byte readEEByte( __builtin_tblpage(eeData), __builtin_tbloffset(eeData) + byte_pointer - 1, &word_data); //=========================================================== word_data = ((unsigned int)buf[0] << 8) + (0xFF & word_data); byte_wr++; //Update buffer pointer byte_pointer++; //Update global pointer } else if(i==max_write-1 && ((isOddAddr && sOddByte==0)||(isOddAddr==0 && isOddByte))){ //Last byte not used //=============================================save last byte readEEByte( __builtin_tblpage(eeData), __builtin_tbloffset(eeData) + byte_pointer + 1, &word_data); //============================================================ word_data = (word_data << 8) + buf[byte_wr]; byte_wr++; //Update buffer pointer byte_pointer++; //Update global pointer } else{ //Both bytes valid word_data = ((unsigned int)buf[byte_wr+1] << 8) + buf[byte_wr]; byte_wr+=2; //Update buffer pointer byte_pointer+=2; //Update global pointer } //================================================================== eraseEEWord( __builtin_tblpage(eeData), __builtin_tbloffset(eeData) + 2*word_offset); writeEEWord( __builtin_tblpage(eeData), __builtin_tbloffset(eeData) + 2*word_offset, &word_data); //================================================================== } return byte_wr; //No. of byte written }
- eraseEEWord and writeEEWord are implemented in assembly.
.global _eraseEEWord _eraseEEWord: push TBLPAG mov w0, NVMADRU ;w0 = base of eeData mov w1, NVMADR ;w1 = offset for eeData in word mov #0x4044, w0 mov w0, NVMCON ;Set to erase operation push SR ;Disable global interrupts mov #0x00E0, w0 ior SR mov #0x55, w0 ;Write the KEY sequence mov w0, NVMKEY mov #0xAA, w0 mov w0, NVMKEY bset NVMCON, #15 ;Start the erase cycle, bit 15 = WR nop nop L1: btsc NVMCON, #15 ;while(NVMCONbits.WR) bra L1 clr w0 pop SR ;Enable global interrupts pop TBLPAG return
.global _writeEEWord _writeEEWord: push TBLPAG ;w0 = base of eeData mov w0, TBLPAG ;w1 = offset for eeData in byte tblwtl [w2], [w1] ;w2 = pointer to user buffer mov #0x4004, w0 ;Set to write operation MOV w0, NVMCON push SR ;Disable global interrupts mov #0x00E0, w0 ior SR mov #0x55, w0 ;Write the KEY sequence mov w0, NVMKEY mov #0xAA, w0 mov w0, NVMKEY bset NVMCON, #15 ;Start the erase cycle, bit 15 = WR nop nop L2: btsc NVMCON, #15 ;while(NVMCONbits.WR) bra L2 clr w0 pop SR ;Enable global interrupts pop TBLPAG return
DSP Library
- Library functions in <dsp.h> include the following categories:
- Vector
- Window
- Matrix
- Filtering
- Transform
- 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)
Overflow and Saturation Traps
Build-in Library
- Some assembler operators can only be accessed by inline assembly code, for example,
- Manuipulation of accumulators A and B (add, sub, mul, divide, shift, clear, square)
- Bit toggling
- Access to psv (program space visiblity) page and offset
- Access to table instruction page and offset
- Built-in functions are written as C-like function calls to utilize these assembler operators.
Bootloader Development
Concepts
- Programming with ICSP is useful when the target board is produced in batch. The producer can download a program even when the chip is on the target board.
- However, ICSP requires an external programmer.
- To allow the user to change the program after production but without the need of an external programmer, bootloader becomes useful.
- Bootloader is a small program installed via ICSP. Everytime the device is reset, the bootloader is run first. The bootloader first detects the default serial channel whether the user wishes to download a new program to the device. If so, the bootloader will pause there, and wait for the user to download the hex file from the PC. The hex file is written to the device via RTSP instructions in the bootloader. If a new download is not necessary, the bootloader redirects to the previously installed user's program.
- The disadvantage of bootloaders is that they consume some of the memory of the device.
Developer | Source | Platform | User Guide | Remarks |
---|---|---|---|---|
ingenia | Assembly | Windows |
| |
Tiny | Assembly | Windows | Web |
|
Elektronika | Hex | Windows | txt |
|
dsPicBootloader
- The bootloader developed by ingenia is open source and it has been modified (see below) to suit our development using dsPic30f5011.
- The bootloader (hereafter called dsPicBootloader) employs the following settings:
- Use U2ART channel
- Use FRC, PLL16
- For 5011, the bootloader is located between 0x00AE00 to 0x00AFFE (512bytes). Refer to C:\Program Files\Ingenia\ingeniadsPICbootloader\ibl_dspiclist.xml after installing the GUI interface.
- Changes made to assembly code includes:
1. including p30f5011.gld and p30f5011.inc
.include "p30f5011.inc"
2. changing the config code of UART #0x8420 -> #0x8020
; Uart init mov #0x8020, W0 ; W0 = 0x8020 -> 1000 0000 0010 0000b mov W0, U2MODE ; Enable UART, AutoBaud and 8N1 clr U2STA
3. changing the start address 0xAE00 - 0x0100 = 0AD00
.equ CRC, W4 .equ ACK, 0x55 .equ NACK, 0xFF .equ USER_ADDRESS, 0x0100 .equ START_ADDRESS, 0xAD00 ; Relative to 0x0100
4. using Internal FRC and PLL16
config __FOSC, CSW_FSCM_OFF & FRC_PLL16 ;Turn off clock switching and ;fail-safe clock monitoring and ;use the Internal Clock as the ;system clock
5. disabling MCLR (optional)
config __FBORPOR, PBOR_ON & BORV_27 & PWRT_16 & MCLR_DIS ;Set Brown-out Reset voltage and ;and set Power-up Timer to 16msecs
6. changing all the related registers of U1ART to U2ART, all U1XXX => U2XXX
U2MODE, U2STA, U2BRG, U2RXREG, U2TXREG
7. changing all the related registers of IC1 to IC2, all IC1XXX => IC2XXX
IC2CON, #IC2IF, #IC2IE
dsPicProgrammer (Java-based Mulit-Platformed)
- Ingenia developed a programmer (PC-side) that works only in Windows environment. The project for Linux environment is currently suspended.
- A simple programmer (hereafter called dsPicProgrammer) written in Java based on the library developed by RXTX has been developed here. The programmer supports both Linux and Windows environments, and may be used as a substitution for the official programmer developed by ingenia.
- The programmer has the following specification and limitations:
- Use baud rate of 57600bps (Not selectable).
- Only program dsPic30f5011 devices (Developers may change the source code for your devices).
- Protection against overwriting bootloader codes on devices.
Downloads
Program | Download | Remarks |
---|---|---|
dsPicBootloader | click here | Under "dsPicBootloader/", download ingenia.s and compile yourself |
dsPicProgrammer | click here | Under "dsPicProgrammer/", dowload dsPicProgrammer.jar Alternatively, if you want to compile yourself or modify the source code, download COMDataHandler.java, COMPortManager.java, Pic5011Prog.java, Pic5011Protocol.java, and WriteBuffer.java under "dsPicProgrammer/" plus RdFileIntelHex.java under "IntelHexPaser/tags/0.02.00/". You should also install RXTX on your local machine as recommended in the readme file. |
Communication Protocol
- Communication Protocol is reviewed in ingenia bootloader user's guide section 2.1.3. The following summarises the key steps on the PC side (Refer also to section 2.2.2).
- Transmission is conducted in 8N1, i.e. 8-bit, no parity, 1 stop-bit
- Stage 1: User's configuation
- Select a baudrate
- Select a COM port channel
- Stage 2: Autobaud rate detection and version control
- Continuously sending a character "U" [0x55] via COM port
- Continuously waiting for an acknowledgment character "U", [ACK] = [0x55]
- Send command character [0x03]
- Receive 3 characters 1) Major Version 2) Minor Version 3) Acknowledgment [0x55]
- Prints the version number [Major.Minor] (e.g. 1.1) on screen.
- Stage 3: Loading and writing the program
- Load the user hex file, check integrity.
- Start loading file using:
- Read command character [0x01] + 24-bit address [High][Medium][Low]
- Receive 4-byte data [High][Medium][Low][ACK]
- Write command character [0x02] + 24-bit address [High][Medium][Low]+ Number of bytes [N] + [data 0] + [data 1] + ... + [data N-1] + [CRC]=(INTEL HEX8 Checksum - Sum modulo 256)
- Recieve [ACK] or [NACK] = [0xFF]
- Note: Writing is in row mode access (i.e. erase and write a whole row, each row has 32 instructions, or 96 bytes because each instruction has 24 bits)
- Ensure the initial address of writing match an initial row position,
- Send the data corresponding to the whole row.
USB-RS232 Interface
- As USB ports are becoming more and more common, COM ports and Parallel ports may be redundant in the next few years. This section explore the possibilities of programming the target board through a USB port.
- There are two options:
- Use an external USB/RS232 adaptor, the driver will emulate a virtual COM port, such as Prolific and FDTI. Ingenia has tested its bootloader with some USB-232 manufacturers (silabs, FTDI, etc..). However, the programming failed with our Prolific adapter. Application program may use JavaComm API (javax.comm) and/or RXTX to drive the COM port.
- Modified the bootloader program on PC to support USB communication. e.g. using jUSB and JSR-80 (javax.usb). External circuits such as PIC18F4550 and MAX232 are required.
|--User's App.--|-------Device Manager------|-------USB-RS232 Interface------|---dsPIC---| Option 1: +-------------+ +----------+ +----------+ +---+ +------------+ +-----+ +--------+ | Application |--| JavaComm |--| Virtual |==|USB|--| FDTI |--|RS232|==| Target | | Program | | RXTX | | COM Port | +---+ | Circuitary | +-----+ | Board | +-------------+ +----------+ +----------+ +------------+ +--------+ Option 2: +-------------+ +--------+ +---+ +------------+ +-----+ +--------+ | Application |----------| JSR-80 |==========|USB|--| PIC18F4550 |--|RS232|==| Target | | Program | | jUSB | +---+ | MAX232 | +-----+ | Board | +-------------+ +--------+ +------------+ +--------+
- Currently, when RXTX is incorporated with JavaComm API, operating systems supported include Linux, Windows, Mac OS, Solaris and other operating systems. On the other hand, jUSB and JSR-80 only works for linux.
FDTI Chips
- FT2232D communicate with PC via USB to provide 2 COM Port channels.
- Datasheets can be downloaded here.
- Virtual COM Port Drivers can be downloaded here.
Programming the Device
Requirements
- Hardware
- PC with COM port (Windows XP Installed)
- ICD2 Programmer
- Target Board
- 5V Power Supply
- Software
- Files
- Modified ingenia bootloader (ingenia.hex). Original assembly code can be downloaded from here.
- Application hex file (e.g. app.hex)
Procedures
Loading Bootloader
- Install MPLAB IDE on PC
- Do NOT connect ICD 2 (via USB) to PC
- Execute MPLAB vX.XX Install.exe
- Install USB Driver for ICD 2
- Follow the instruction in (C:\Program Files\Microchip\MPLAB IDE\ICD2\Drivers\Ddicd2.htm)
- Run MPLAB IDE on PC
- Select target chip
- Select: Configure>Select Devices...
- Choose dsPIC30F5011
- Plug-in ICD 2 to PC (USB)
- Do NOT connect target (via 6-pin cable) to ICD 2
- Select ICD 2 as the current programmer
- Select: Programmer>Select Programmer>MPLAB ICD 2
- If this is the first time the ICD 2 is connected to PC, MPLAB IDE will automatically download the required OS to ICD 2, wait until it has finished
- You should also see Warnings on invalid device IDs, and/or running self tests. Ignore these warnings since the target board has not been connected yet.
- Place Jumper on target board
- Connect target board to ICD 2 (via six pin cable)
- Beware of the pin assignments. Only pin 1 - 5 should be used.
- Power-up the Target
- Establish connection with target
- On MPLAB IDE, Select Programmer>Connect
- See results of self test: Programmer>Settings, Status Tab. Refer to ICD2 User's Guide Chapter 7.
- Load the bootloader hex file ingenia.hex on MPLAB IDE
- Select: File>Import...
- Download the bootloader to target board
- Select: Programmer>Program
- Power-down the Taget.
- Disconnect ICD 2 from PC
- Select: Programmer>Select Programmer>None
- Unplug USB cable
Loading Application
- Install ingenia dsPIC bootloader GUI on PC
- Execute ingeniadsPICbootloader.exe
- Connect target board to COM Port
- Power-down target board
- Run ingenia dsPIC bootloader GUI
- Press "OK, my platform is shut down" in Dialog 0
- Select COM port and baud rate in Dialog 1
- Power-up target board in Dialog 2
- Load the app.hex by pressing Open in Dialog 3
- Download the hex file by pressing Write in Dialog 3
- Power-down target board and disconnect from COM port
To Do List
- Explore the possibilities of using USB/RS232 interface
- Construct examples codes for using DSP library
- Construct examples codes for using Build-in library
- Review on standard means to access remote and local devices