Difference between revisions of "DsPIC30F 5011 Development Board"

From OpenCircuits
Jump to navigation Jump to search
m (Reverted edits by ColeenRosales (Talk) to last revision by Russ hensel)
 
(105 intermediate revisions by 19 users not shown)
Line 1: Line 1:
 +
This project aims to provide the development tools for building a [[Multi-purpose_Embedded_System | multi-purpose MCU board]]. Description is based on Microchip dsPic33FJ256GP506 (was dsPic30F5011), but information provided in this wiki may give useful directions for developing similar embedded systems with different platforms.
 +
 
==Introduction==
 
==Introduction==
  
===Features of dsPIC30F5011===
+
===Features of dsPic33FJ256GP506===
*2.5 to 5V
+
*3.0 to 3.3 V
*Up to 30MIPs
+
*Up to 40 MIPs
*High current/sink source I/O pins: 25mA
+
*Maximum current sink/source for I/O pins: 4 mA
 +
*16-bit arithmetics
 
*DSP Instruction Set
 
*DSP Instruction Set
 
*Dual programming techniques: ICSP and RTSP
 
*Dual programming techniques: ICSP and RTSP
*UART: up to 2 modules
+
*Memory
*I<sup>2</sup>C: up to 1Mbps
+
**256&nbsp;KB flash (86K instructions)
 +
**16&nbsp;KB RAM (incl. 2&nbsp;KB DMA RAM)
 +
**No EEPROM
 +
*Communications ports
 +
**UART
 +
**I<sup>2</sup>C: up to 1&nbsp;Mbit/s
 +
**SPI
 +
*ADC
 
*10-bit A/D, 1.1 Msps
 
*10-bit A/D, 1.1 Msps
*12-bit A/D, 200 ksps
+
*12-bit A/D, 500 ksps
*44K flash (66Kb), 4Kb RAM, 1Kb EEPROM
+
*No DAC (PWMs only)
*No DAC
 
 
*Pin-to-pin compatible with other dsPICs
 
*Pin-to-pin compatible with other dsPICs
 
{| border="1" cellspacing="0" cellpadding="5"
 
{| border="1" cellspacing="0" cellpadding="5"
|+ Table 1.1 Comparison with Compatible dsPICs
+
|+ Comparison between different dsPICs
! dsPic !! Price<br>US$ !! MIPs
+
! dsPic !! *Price<br>US$ !! MIPs
 
! Flash<br>(kB)!! RAM<br>(kB) !! EEPROM<br>(kB)
 
! Flash<br>(kB)!! RAM<br>(kB) !! EEPROM<br>(kB)
 
! I/O !! ADC<br>12-bit !! IC !! OC !! Motor<br>Ctrl !! Timers
 
! I/O !! ADC<br>12-bit !! IC !! OC !! Motor<br>Ctrl !! Timers
 
! QEI !! UART !! SPI !! I2C !! CAN !! Codec
 
! QEI !! UART !! SPI !! I2C !! CAN !! Codec
|-
 
| 30F5011 || 5.91 || 30
 
| 66 || 4 || 1
 
| 52 || 16 || 8 || 8 || 0 || 5x16bit<br>2x32bit
 
| 0 || 2 || 2 || 1 || 2 || 1
 
 
|-
 
|-
| 30F6011A || 7.73 || 30
+
| 33FJ256GP506 || 6.11 || 40
| 132 || 6 || 2
+
| 256 || 16 || 0
| 52 || 16 || 8 || 8 || 0 || 5x16bit<br>2x32bit
+
| 53 || 18 || 8 || 8 || 0 || 9x16bit<br>4x32bit
| 0 || 2 || 2 || 1 || 2 || 0
+
| 0 || 2 || 2 || 2 || 1 || 1
|-
 
| 30F6012A || 7.85 || 30
 
| 144 || 8 || 4
 
| 52 || 16 || 8 || 8 || 0 || 5x16bit<br>2x32bit
 
| 0 || 2 || 2 || 1 || 2 || 1
 
 
|-  
 
|-  
 
| 33FJ128GP206 || 4.62 || 40
 
| 33FJ128GP206 || 4.62 || 40
Line 60: Line 59:
 
| 53 || 16 || 8 || 8 || 8 || 9x16bit<br>4x32bit
 
| 53 || 16 || 8 || 8 || 8 || 9x16bit<br>4x32bit
 
| 1 || 2 || 2 || 2 || 1 || 0
 
| 1 || 2 || 2 || 2 || 1 || 0
|-
 
| 33FJ256GP506 || 6.11 || 40
 
| 256 || 16 || 0
 
| 53 || 18 || 8 || 8 || 0 || 9x16bit<br>4x32bit
 
| 0 || 2 || 2 || 2 || 1 || 1
 
 
|-
 
|-
 
|}
 
|}
+
<nowiki>*</nowiki>For reference only, subject to change
===Web Page===
 
*[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2529&param=en024856 Microchip Official Website]
 
  
===Forum===
+
===Forums===
*[http://direct.forum.microchip.com/default.aspx Microchip]: Official forum by Microchip
+
*[http://forum.microchip.com/ Microchip]: Official forum by Microchip
**[http://direct.forum.microchip.com/tt.aspx?forumid=49 MPLAB ICD 2]: Subforum on ICD 2 programmer
+
**See MPLAB ICD 2, MPLAB IDE, MPLAB C30 Compiler, ASM30, Link30 forum, dsPIC30F Topics, dsPic33 topics
**[http://direct.forum.microchip.com/tt.aspx?forumid=57 MPLAB IDE]: Subforum on IDE
 
**[http://direct.forum.microchip.com/tt.aspx?forumid=101 MPLAB C30 Compiler, ASM30, Link30 forum]: Subforum on C compiler. Refer to [http://ww1.microchip.com/downloads/en/DeviceDoc/C30_Users_Guide_51284e.pdf MPLAB C30 C Compiler User's Guide] Chapter 3
 
**[http://direct.forum.microchip.com/tt.aspx?forumid=153 dsPIC30F Topics]: Subformum on dsPIC30F
 
*[http://www.gnupic.org/ GNUPIC]: Discussion on PIC in Linux Systems
 
**[http://www.linuxhacker.org/cgi-bin/ezmlm-cgi?1:dds:5443#b Debian]
 
 
*[http://www.htsoft.com/forum/all/ubbthreads.php/Cat/0/C/6 HI-TECH Software Forum]: Discussion on dsPICC, a C compiler developed by HI-TECH
 
*[http://www.htsoft.com/forum/all/ubbthreads.php/Cat/0/C/6 HI-TECH Software Forum]: Discussion on dsPICC, a C compiler developed by HI-TECH
*[http://piclist.com/techref/piclist/index.htm PICList]: Discussion on older PIC systems (not dsPIC)
+
*[http://sourceforge.net/forum/forum.php?forum_id=382005 FreeRTOS Real Time Kernel]: Open Discussion and Support on FreeRTOS
*[http://groups.google.com/group/pickit-devel PicKit]: Discussion on PICkit/PICkit 2 programmers
+
*[http://www.nabble.com/MicroControllers---GNUPIC-f2057.html Nabble]: MicroControllers - GNUPIC
*[http://sourceforge.net/forum/forum.php?forum_id=382005 FreeRTOS Real Time Kernel]: Open Discussion and Support on FreeRTOS
 
  
 
===References===
 
===References===
*dsPIC30F
 
**[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2574 dsPIC30F Family Reference Manual Sections]: Contains detailed descriptions on dsPIC30F register definitions and example codes
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80169E.pdf dsPIC30F Family Reference Manual Errata (Use with revision 70046B only)]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70116F.pdf dsPIC30F5011, dsPIC30F5013 Data Sheet]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80210e.pdf dsPIC30F5011/5013 Rev. A1/A2 Silicon Errata]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80223D.pdf dsPIC30F5011/5013 Rev. A3 Silicon Errata]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70102G.pdf Flash Programming Specification]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70157B.pdf dsPIC30F Programmer's Reference Manual]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80170a.pdf dsPIC30F Programmer's Reference Manual Errata (use with revision DS70030E only)]
 
 
 
*dsPIC33F
 
*dsPIC33F
 
**[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2573 dsPIC33F Family Reference Manual Sections]
 
**[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2573 dsPIC33F Family Reference Manual Sections]
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70165E.pdf dsPIC33F Family Data Sheet]
+
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70286C.pdf dsPIC33FJXXXGPX06/X08/X10 Data Sheet]
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80279B.pdf dsPIC33F Rev. A2 Silicon Errata]
+
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80306E.pdf dsPIC33FJXXXGPX06/X08/X10 Rev. A2/A3/A4 Silicon Errata]
**[http://ww1.microchip.com/downloads/en/DeviceDoc/80306A.pdf dsPIC33FJXXXGPX06/X08/X10 Rev. A2 Silicon Errata]
+
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70152G.pdf Flash Programming Specification]
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70152C.pdf Flash Programming Specification]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/70172A.pdf dsPIC30F to dsPIC33F Conversion Guidelines]
 
 
*ICD2 Programmer
 
*ICD2 Programmer
**[http://ww1.microchip.com/downloads/en/DeviceDoc/51331B.pdf ICD2 User's Guide]
+
**[http://ww1.microchip.com/downloads/en/DeviceDoc/51331C.pdf ICD2 User's Guide]
 
*MPLAB
 
*MPLAB
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/51519B.pdf MPLAB IDE User's Guide]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/51519B.pdf MPLAB IDE User's Guide]
Line 110: Line 84:
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/16bit_Language_Tool_Libraries_51456c.pdf 16-bit Language Tools Libraries]: Contains summaries and examples of using DSP libraries, standard C libraries and device libraries
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/16bit_Language_Tool_Libraries_51456c.pdf 16-bit Language Tools Libraries]: Contains summaries and examples of using DSP libraries, standard C libraries and device libraries
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/Asm30_Link_Util_51317e.pdf MPLAB ASM30, MPLAB LINK30 and Utilities User's Guide]
 
**[http://ww1.microchip.com/downloads/en/DeviceDoc/Asm30_Link_Util_51317e.pdf MPLAB ASM30, MPLAB LINK30 and Utilities User's Guide]
**[http://ww1.microchip.com/downloads/en/DeviceDoc/51322d.pdf dsPIC30F Language Tools Quick Reference Card]
 
  
 
===Code Examples===
 
===Code Examples===
 
*[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1408 Microchip Example Codes for dsPic]
 
*[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1408 Microchip Example Codes for dsPic]
 +
 +
===Related Development===
 +
*[[Ethernet Module]]
 +
*[[Modulation Plugin]]
  
  
Line 127: Line 104:
 
**Required low-level programming to erase, program and verify the chip.
 
**Required low-level programming to erase, program and verify the chip.
 
**Slower, because codes are serially executed.
 
**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
 
*Enhanced ICSP
Line 138: Line 114:
 
====Hardware Interface====
 
====Hardware Interface====
 
{| border="1" cellspacing="0" cellpadding="5"
 
{| border="1" cellspacing="0" cellpadding="5"
|+ Table 2.1 Pin Used by ICSP
+
|+ Pin Used by ICSP
 
! Pin Label !! Function !! Pin Number
 
! Pin Label !! Function !! Pin Number
 
|-  
 
|-  
Line 155: Line 131:
  
 
{| border="1" cellspacing="0" cellpadding="5"
 
{| border="1" cellspacing="0" cellpadding="5"
|+ Table 2.2 Available Programmers in the Market
+
|+ Available Programmers in the Market
 
! Product Name
 
! Product Name
 
! Interface with PC
 
! Interface with PC
 
! Interface with Device
 
! Interface with Device
! Price (US)
+
! *Price (US)
! Postage (US)
+
! Remarks
! Total (US)
 
 
|-  
 
|-  
 
| [http://direct.www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010046&part=DV164005 MPLAB<sup>®</sup> ICD 2]
 
| [http://direct.www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010046&part=DV164005 MPLAB<sup>®</sup> ICD 2]
Line 168: Line 143:
 
| $159.99
 
| $159.99
 
| -
 
| -
| -
 
|-
 
| [http://www.etekronics.com/product_info.php?cPath=24&products_id=48  Full Speed USB Microchip ICD2<br> Debugger and Programmer]
 
| USB
 
| 6-PIN ICSP connector<br>6-PIN RJ-12 connector
 
| $72.00
 
| $12.00
 
| $84.00
 
|-
 
| [http://www.etekronics.com/product_info.php?cPath=24&products_id=47 Mini Microchip Compatible ICD2<br> Debugger and Programmer]
 
| RS232
 
| 6-PIN ICSP connector<br>6-PIN RJ-12 connector
 
| $45.00
 
| $10.00
 
| $55.00
 
|-
 
| [http://www.inexglobal.com/microcontroller.php ICDX30]
 
| RS232
 
| 6-pin RJ-11
 
| $51.00
 
| $47.46
 
| $98.46
 
 
|-
 
|-
| [http://www.sure-electronics.net/englishsite/icd2/icd2.htm Clone Microchip ICD2]
+
| [http://www.sureelectronics.net Clone Microchip ICD2] (Now Using)
 
| USB
 
| USB
 
| 6-pin flat cables
 
| 6-pin flat cables
| $30.00
+
| $52.35
| $12.00
+
| Do not work with new MPLAB versions (works for 7.50), communication to MPLAB may sometime hang (see [http://www.sureelectronics.net/pdfs/DB-DP003.pdf manual])
| $42.00
 
 
|-
 
|-
 
|}
 
|}
 +
<nowiki>*</nowiki>For reference only (exclude shipping), subject to change
  
  
 
{| border="1" cellspacing="0" cellpadding="5"
 
{| border="1" cellspacing="0" cellpadding="5"
|+ Table 2.3 DIY ICD 2 Programmer Circuit
+
|+ DIY ICD 2 Programmer Circuit
 
! Source !! Schematic !! PIC16F877A Bootloader
 
! Source !! Schematic !! PIC16F877A Bootloader
 
|-  
 
|-  
Line 214: Line 167:
 
|-
 
|-
 
|}
 
|}
 +
  
 
====Software Interface====
 
====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.
 
*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.
 
  
 
{| border="1" cellspacing="0" cellpadding="5"
 
{| border="1" cellspacing="0" cellpadding="5"
|+ Table 2.4 Summary of IDE
+
|+ Summary of IDE
 
! Product Name !! Features !! OS !! Price (US$)
 
! Product Name !! Features !! OS !! Price (US$)
 
|-  
 
|-  
Line 233: Line 186:
 
| $895.00 (Free student version<sup>1</sup>)
 
| $895.00 (Free student version<sup>1</sup>)
 
|-
 
|-
| [http://linux.softpedia.com/get/Science-and-Engineering/Electronic-Design-Automation-EDA-/Piklab-8099.shtml Piklab 0.12.0]
+
| [http://piklab.sourceforge.net/ Piklab]
 
| Assembler and C-Compiler
 
| Assembler and C-Compiler
 
| Linux
 
| Linux
| Free<sup>2</sup>
+
| Free
 
|}
 
|}
 
# Full-featured for the first 60 days. After 60 days, some code optimization functions are disabled. The compiler will continue to function after 60 days, but code size may increase.
 
# Full-featured for the first 60 days. After 60 days, some code optimization functions are disabled. 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: COM Port (Bootloader)===
 
*RTSP works in normal voltage (MCLR# no need to raise to V<sub>IHH</sub>).
 
*RTSP works in normal voltage (MCLR# no need to raise to V<sub>IHH</sub>).
 
*No literature has mentioned the incorporation of Programming Executive (PE). Presumably, since Enhanced ICSP needs to set MCLR# to V<sub>IHH</sub>, RTSP cannot use PE.
 
*No literature has mentioned the incorporation of Programming Executive (PE). Presumably, since Enhanced ICSP needs to set MCLR# to V<sub>IHH</sub>, RTSP cannot use PE.
*Refer to [http://www.opencircuits.com/DsPIC30F_5011_Development_Board#Bootloader_Development bootloader section].
+
*Refer to [[DsPIC30F_5011_Development_Board#Bootloader_Development | bootloader section]].
 
 
 
 
==IC Requirements==
 
{|border="1" cellspacing="0" cellpadding="5"
 
|+ Table 3.1 IC Requirements
 
! Part No. !! Description
 
! Min Temp !! Max Temp !! Min Volt !! Max Volt !! Typ Cur !! Max Cur
 
|-valign="top"
 
| [http://ww1.microchip.com/downloads/en/DeviceDoc/70116F.pdf dsPIC30F5011-30I/PT] || uP
 
| -40<sup>o</sup>C || 85<sup>o</sup>C
 
| 2.5V <sup>[1]</sup>|| 5.5V
 
|  145mA  || 217mA
 
|-
 
| [http://datasheets.maxim-ic.com/en/ds/MAX3222-MAX3241.pdf MAX3232ESE] || RS232 driver
 
| -40<sup>o</sup>C || 85<sup>o</sup>C
 
| 3.0V || 5.5V
 
| 0.3mA || 1.0mA
 
|-
 
| [http://www.national.com/ds.cgi/DS/DS3695.pdf DS3695N] || RS485 driver
 
| -40<sup>o</sup>C || 85<sup>o</sup>C
 
| 4.75V || 5.25V
 
| 42mA || 60mA
 
|-
 
| [http://focus.ti.com/lit/ds/symlink/dac6574.pdf DAC6574IDGS] || 10-bit Quad-DAC I<sup>2</sup>C
 
| -40<sup>o</sup>C || 105<sup>o</sup>C
 
| 2.7V || 5.5V
 
| 0.6mA || 0.9mA
 
|-
 
| [http://www.semiconductors.philips.com/acrobat/datasheets/74HC_HCT14_3.pdf 74HC14D] || Quad-Schmitt Trigger
 
| -40<sup>o</sup>C || 125<sup>o</sup>C
 
| 2.0V || 6.0V
 
| || 0.02mA
 
|-
 
| '''Overall''' ||
 
| '''-40<sup>o</sup>C''' || '''85<sup>o</sup>C'''
 
| '''4.75V''' || '''5.25V'''
 
| || '''<300mA <sup>[2]</sup>'''
 
|-
 
| [http://ww1.microchip.com/downloads/en/DeviceDoc/70165E.pdf dsPIC33FJ128GP306-I/PT] || uP
 
| -40<sup>o</sup>C || 85<sup>o</sup>C
 
| 3.0V <sup>[1]</sup>|| 3.6V
 
| 74mA  || 250mA
 
|-
 
| [http://www.analog.com/UploadedFiles/Data_Sheets/ADM3485E.pdf ADM3485EARZ] || RS485 driver
 
| -40<sup>o</sup>C || 85<sup>o</sup>C
 
| 3.0V || 3.6V
 
| 1.1mA || 2.2mA
 
|-
 
|}
 
#Minimum voltage measured is 3.3V (with 2 LEDs blinking) running at 30MHz.
 
#Measured current at 5V is 180mA (with 2 LEDs blinking only)
 
  
  
Line 312: Line 213:
  
 
*Microchip has integrated ASM30, LINK30, assembly header files, linker scripts in MPLAB IDE, which is free for download.
 
*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.
+
*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.
  
 
*C-libraries contained in C30 includes (Refer to [http://ww1.microchip.com/downloads/en/DeviceDoc/16bit_Language_Tool_Libraries_51456c.pdf 16-Bit Language Tools Libraries] from Microchip).
 
*C-libraries contained in C30 includes (Refer to [http://ww1.microchip.com/downloads/en/DeviceDoc/16bit_Language_Tool_Libraries_51456c.pdf 16-Bit Language Tools Libraries] from Microchip).
Line 318: Line 219:
  
 
{|border="1" cellspacing="0" cellpadding="5"
 
{|border="1" cellspacing="0" cellpadding="5"
|+ Table 4.1 C Libraries in MPLAB C30
+
|+ C Libraries in MPLAB C30
 
! Library !! Directory <br>(\\Microchip\MPLAB C30) !! Major functions
 
! Library !! Directory <br>(\\Microchip\MPLAB C30) !! Major functions
 
|-valign="top"
 
|-valign="top"
Line 325: Line 226:
 
| Vector, Matrix, Filter, etc.
 
| Vector, Matrix, Filter, etc.
 
|-valign="top"
 
|-valign="top"
| 16-Bit Peripheral Libraries <br>(e.g. libp30F5011-coff.a)
+
| 16-Bit Peripheral Libraries
 
| \lib <br> \src\peripheral <br> \support\h
 
| \lib <br> \src\peripheral <br> \support\h
 
| ADC12, IOPort, UART, I<sup>2</sup>C, etc.
 
| ADC12, IOPort, UART, I<sup>2</sup>C, etc.
Line 347: Line 248:
 
**Current MPLAB ASM30 Assembler: v2.04
 
**Current MPLAB ASM30 Assembler: v2.04
 
**Current MPLAB C30 Compiler: v2.04
 
**Current MPLAB C30 Compiler: v2.04
 +
*'''Important Note''': Only the compiler is free. The header files and library are owned by Microchip.
  
*[http://gcc.gnu.org/ml/gcc/2005-02/msg01144.html 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.
+
{|border="1" cellspacing="0" cellpadding="5"
**Download '''pic30-1.32-debian.tar.bz2''' for Template v1.32. (For v2.01, please goto [http://thread.gmane.org/gmane.comp.hardware.microcontrollers.gnupic/3768/focus=3768  pic30-debian-2.01.tar.bz2]).
+
|+ Pic30 C-Compiler Toolchain Templates for Conversion to Debian-based systems
**Download '''pic30-binutils_1.32-1_i386.deb''' for the assember.
+
! Toolchain Source !! Instruction !! Remarks
**Download '''pic30-gcc_1.32-1_i386.deb''' for the compiler.
+
|-valign="top"
 +
| [http://www.baycom.org/~tom/dspic/ v2.00]
 +
| Download pic30-gcc-2.00-1.i386.rpm and pic30-binutils-2.00-1.i386.rpm.<br>Convert to deb files.
 +
| Stable<br>Now using
 +
|-valign="top"
 +
| [http://www.nabble.com/Debian-templates-for-dsPIC-build-toolchain-2.05-td7886279.html v2.05]
 +
| Reference to example below, but use 2.05 files
 +
| Can compile<br>Stable but not heavily tested
 +
|-valign="top"
 +
| [http://www.nabble.com/Debian-templates-for-dsPIC-build-toolchain-3.01-tf4308624.html v3.01]
 +
| Follow example below
 +
| Can compile<br>Unstable (sometime produce segmentation fault)
 +
|-valign="top"
 +
| [http://www.nabble.com/Debian-Template-Patches-for-C30-v3.10-i386-td17534084.html v3.10]
 +
| Reference to example below, but use 3.10 files
 +
| Cannot compile yet (segmentation fault)
 +
|-
 +
|}
 +
====Conversion Example====
 +
*Pre-install these packages: dpkg-dev, debhelper, bison, flex, sysutils, gcc-3.3, fakeroot
 +
**cmd: '''sudo apt-get install dpkg-dev debhelper bison flex sysutils gcc-3.3 fakeroot'''
 +
*Download and unzip template: '''pic30-3.01.tar.bz2'''
 +
*Download assembler: '''mplabalc30v3_01_A.tar.gz'''. Save under /pic30-3.01/pic30-binutils-3.01/upstream/
 +
*Download c-compiler: '''mplabc30v3_01_A.tgz'''. Save under /pic30-3.01/pic30-gcc-3.01/upstream/
 +
*Install MPLAB_C30_v3_01-StudentEdition under Windows
 +
*Copy directories /include, /lib, /support, and /bin/c30_device.info to pic30-3.01/pic30-support-3.01/upstream/
 +
*Pack pic30-binutils into deb file
 +
**goto /pic30-3.01/pic30-binutils-3.01/
 +
**type cmd: '''dpkg-buildpackage -rfakeroot -b'''
 +
*Install pic30-binutils_3.01-1_i386.deb
 +
**type cmd: '''sudo dpkg -i pic30-binutils_3.01-1_i386.deb'''
 +
*Pack pic30-gcc-3.01 into deb file
 +
**goto /pic30-3.01/pic30-gcc-3.01/
 +
**type cmd: '''dpkg-buildpackage -rfakeroot -b'''
 +
*Install pic30-gcc_3.01-1_i386.deb
 +
**type cmd: '''sudo dpkg -i pic30-gcc_3.01-1_i386.deb'''
 +
*Pack support files into deb file
 +
**goto /pic30-3.01/pic30-support-3.01/
 +
**type cmd: '''dpkg-buildpackage -rfakeroot -b'''
 +
*Install pic30-support_3.01-1_all.deb
 +
**type cmd: '''sudo dpkg -i pic30-support_3.01-1_all.deb'''
 +
*After installation, locations of
 +
**C-Header (*.h): /usr/pic30-elf/include
 +
**Libraries (*.a): /usr/pic30-elf/lib
 +
**Assembly header (*.inc): /usr/share/pic30-support/inc
 +
**Linkerscript (*.gld): /usr/share/pic30-support/gld
  
*'''Important Note''': Only the compiler is free. The header files and library is owned by Microchip.
+
===Burning Program Codes to Target Board===
**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 [http://www.baycom.org/~tom/dspic/ here].
 
**Instructions for filling the upstream direction is available [http://forum.microchip.com/printable.aspx?m=139360 here].
 
**Alteratively, [https://gna.org/projects/pic30-libc/ 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 [http://homerreid.ath.cx/misc/dspicprg/ Homer Reid] to burn hex code (*.hex) to devices. See Reference [http://forum.microchip.com/tm.aspx?m=94243 here]. Through serial port only?
 
#Use 'dspicprg and dspicdmp' utilities developed by [http://homerreid.ath.cx/misc/dspicprg/ Homer Reid] to burn hex code (*.hex) to devices. See Reference [http://forum.microchip.com/tm.aspx?m=94243 here]. Through serial port only?
 
#Use [http://piklab.sourceforge.net/ Piklab IDE]. Details on file format not known.
 
#Use [http://piklab.sourceforge.net/ Piklab IDE]. Details on file format not known.
Line 368: Line 309:
  
 
{|border="1" cellspacing="0" cellpadding="5"
 
{|border="1" cellspacing="0" cellpadding="5"
|+ Table 4.2 Comparison between differnt optimization levels
+
|+ Comparison between differnt optimization levels
 
! Optimization !! Description !! Project 1<br>Code Size<br>(byte) !! Project 1<br>Data Usage<br>(byte) !! Project 2<br>Code Size<br>(byte) !! Project 2<br>Data Usage<br>(byte)
 
! Optimization !! Description !! Project 1<br>Code Size<br>(byte) !! Project 1<br>Data Usage<br>(byte) !! Project 2<br>Code Size<br>(byte) !! Project 2<br>Data Usage<br>(byte)
 
|-valign="top"
 
|-valign="top"
Line 394: Line 335:
  
  
==Software Architecture==
+
==[[freertos_posix Development | Driver Development]]==
                +--------+--------+--------+--------+--------+
+
*Description on developing drivers with POSIX API
  Application  | Task 1 | Task 2 | Task 3 | Task 4 | Task 5 |
 
                +--------+---+----+--------+--------+--------+
 
                |                POSIX API                  |
 
                +-------------------+------------------------+
 
    OS        |    Coroutine      |  FreeRTOS Scheduler  |
 
                +-------------------+------------------------+
 
                |                  Drivers                  |
 
                +------+-----+-----+--------+-------+--------+
 
  Hardware    | UART | ADC | DAC | EEPROM |  PWM  | TIMERS |
 
                +------+-----+-----+--------+-------+--------+
 
*Currently, operating system is based on [http://www.freertos.org/ FreeRTOS] incorporating coroutine developed by [http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html Simon Tatham]
 
*Software Drivers are to be developed to allow users at Application Level to use the hardware (e.g. ADC, DAC, UART, EEPROM etc) through the OS.
 
*The interface between the drivers and the OS is based on [http://www.die.net/doc/linux/man/man2/ POSIX standard] (e.g. open(), write(), read(), ioctl(), usleep() etc).
 
  
  
==Programming Tips==
+
==[[Bootloader Development]]==
 +
*Description on concepts and development on bootloader
 +
*Description on dsPicProgrammer to download firmware via bootloader
  
===Memory Map for 5011===
 
{| border="1" cellspacing="0" cellpadding="5"
 
|+ Table 6.1 Memory Location
 
! Type !! Start Address !! End Address !! Size
 
|-valign="top"
 
| Flash || 0x000000 ||0x00AFFF || 44K<sup>[1]</sup>
 
|-valign="top"
 
| +--Flash: Reset Vector || 0x000000 ||0x000003 || 4
 
|-valign="top"
 
| +--Flash: Interrupt Vector Table || 0x000004 ||0x00007F || 124
 
|-valign="top"
 
| +--Flash: Alternate Vector Table || 0x000084 ||0x0000FF || 124
 
|-valign="top"
 
| +--Flash: User Program || 0x000100 ||0x00AFFF || 43.7K
 
|-valign="top"
 
| EEPROM || 0x7FFC00 || 0x7FFFFF || 1K<sup>[2]</sup>
 
|-valign="top"
 
| Programming Executive || 0x800000 || 0x8005BF || 1472
 
|-valign="top"
 
| Unit ID || 0x8005C0 || 0x8005FF || 64
 
|-valign="top"
 
| Config  Registers || 0xF80000 || 0xF8000F || 16
 
|-valign="top"
 
| Device ID || 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 phathom byte.<br>
 
[2] Each address is 8-bit wide.
 
  
===Data Location===
+
==[[Programming the Device]]==
{| border="1" cellspacing="0" cellpadding="5"
+
*Description on how to use dsPicProgrammer to download firmware to dspic
|+ Table 6.2 Data Location
 
! Type !! Description !! Example
 
|-valign="top"
 
| _XBSS(N) <sup>[1]</sup>
 
| RAM Data in X-memory, aligned at N, no initilization
 
| int _XBSS(32) xbuf[16];
 
|-valign="top"
 
| _XDATA(N) <sup>[1]</sup>
 
| RAM Data in X-memory, aligned at N, with initilization
 
| int _XDATA(32) xbuf[] = {1, 2, 3, 4, 5};
 
|-valign="top"
 
| _YBSS(N) <sup>[1]</sup>
 
| RAM Data in Y-memory, aligned at N, no initilization
 
| int _YBSS(32) ybuf[16];
 
|-valign="top"
 
| _YDATA(N) <sup>[1]</sup>
 
| RAM Data in Y-memory, aligned at N, with initilization
 
| int _YDATA(32) ybuf[16] = {1, 2, 3, 4, 5};
 
|-valign="top"
 
| __attribute__((space(const)))
 
| Flash ROM data, constant, accessed by normal C<br>statements, but 32K max.
 
| int i __attribute__((space(const))) = 10;
 
|-valign="top"
 
| __attribute__((space(prog)))
 
| Flash ROM data, read/write by program space visibility<br>window (psv)
 
| int i __attribute__((space(prog)));
 
|-valign="top"
 
| __attribute__((space(auto_psv)))
 
| Flash ROM data, read by normal C statements, write<br>by accessing psv
 
| int i __attribute__((space(auto_psv)));
 
|-valign="top"
 
| __attribute__((space(psv)))
 
| Flash ROM data, read/write by (psv)
 
| int i __attribute__((space(psv)));
 
|-valign="top"
 
| _EEDATA(N) <sup>[1]</sup>
 
| ROM Data in EEPROM, aligned at N, read/write with psv
 
| int _EEDATA(2) table[]={0, 1, 2, 3, 5, 8};
 
|-valign="top"
 
| _PERSISTENT
 
| RAM Data, data remain after reset
 
| int _PERSISTENT var1, var2;
 
|-valign="top"
 
| _NEAR
 
| RAM Data at near section
 
| int _NEAR var1, var2;
 
|-valign="top"
 
| _ISR
 
| Interrupt service rountine
 
| void _ISR _INT0Interrupt(void);
 
|-valign="top"
 
| _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 F<sub>OSC</sub>
 
*The system clock is divided by 4 to yield the internal instruction cycle clock, F<sub>CY</sub>=F<sub>OSC</sub>/4
 
*FRC with PLLx16 is used to achieve F<sub>CY</sub>=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*F<sub>CY</sub> 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 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
 
  //============================================================
 
  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 [http://www.opencircuits.com/DsPIC30F_5011_Development_Board 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/F<sub>cy</sub>
 
  uxbrg = 1/(Measured Time/8)
 
        = 8*F<sub>cy</sub>/t_count
 
*Since UxBRG is computed by:
 
  UxBRG = (F<sub>cy</sub>/(16*Baudrate)) -1
 
        = (F<sub>cy</sub>/(16*8*F<sub>cy</sub>/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.
 
====open()====
 
*The following structures and variables are used as circular buffers for transmit and receive.
 
  struct UART_Rx{
 
      unsigned char  wr;
 
      unsigned char  rd;
 
  };
 
  struct UART_Tx{
 
      unsigned char  wr;                           
 
      unsigned char  rd;
 
      unsigned char  tx_complete_flag;
 
  };
 
  struct UART_Rx uart_rx;
 
  struct UART_Tx uart_tx;
 
  unsigned char uart_rx_buf[MAX_UART_RX_BUF];
 
  unsigned char uart_tx_buf[MAX_UART_TX_BUF];
 
 
 
  char uart_open()
 
  {
 
      uart_rx.wr = 0;
 
      uart_rx.rd = 0;
 
      uart_tx.wr = 0;
 
      uart_tx.rd = 0;
 
      uart_tx.tx_complete_flag = 1;
 
      uart2_init();
 
      return 0;
 
  }
 
 
 
  void uart2_init(void){
 
      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
 
  }
 
 
 
====write()====
 
*This function writes a series of bytes to the circular buffer and start transmission.
 
  int uart_write(unsigned char *buf, int count)
 
  {
 
      int next_data_pos;
 
      int byte = 0;
 
      for (; byte<count; byte++) {
 
        next_data_pos = pre_wr_cir254buf(  (unsigned char)uart_tx.wr,
 
                                            (unsigned char)uart_tx.rd,
 
                                              MAX_UART_TX_BUF); 
 
        if (next_data_pos!=255) {
 
            //Valid data is available
 
            uart_tx_buf[uart_tx.wr] = (unsigned char) buf[byte];    //copy the char to tx_buf
 
            uart_tx.wr = next_data_pos;                                    //increment the ptr
 
        } else break;
 
      }
 
      //Set transmit complete flag to false
 
      if (uart_tx.tx_complete_flag) {
 
          uart_tx.tx_complete_flag = 0;
 
      }
 
      //Raise Interrupt flag to initiate transmission
 
      _U1TXIF = 1;    //Start interrupt
 
      return byte;       
 
  }
 
*The interrupt routine reads from the circular buffer and send the data. The uart is opened such that the module will generate an TX Interrupt when it a byte is sent.
 
  void _ISR _U2TXInterrupt(void){
 
      _U2TXIF = 0; //Clear Interrupt Flag
 
      unsigned char next_data_pos;
 
      next_data_pos = pre_rd_cir254buf( (unsigned char)uart_tx.wr,
 
                                        (unsigned char)uart_tx.rd,
 
                                        MAX_UART_TX_BUF);
 
      if (next_data_pos!= 255) {
 
        //Valid Data is available to transmit
 
        U2TXREG = (uart_tx_buf[(unsigned char)uart_tx.rd] & 0xFF);  //send next byte...
 
        uart_tx.rd = (unsigned char) next_data_pos;    //update rd pointer
 
      } else {
 
        //Transimission has completed
 
        uart_tx.tx_complete_flag = 1;    // change to empty of tx
 
      }
 
  }
 
 
 
====read()====
 
*The interrupt routine writes to the circular buffer when space is available.
 
  void _ISR _U2RXInterrupt(void){
 
      unsigned char next_data_pos;
 
      if ( U2STAbits.URXDA ){
 
        next_data_pos = pre_wr_cir254buf( uart_rx.wr, uart_rx.rd, MAX_UART_RX_BUF);
 
        if (next_data_pos!=255) {
 
            //If buffer is not full
 
            uart_rx_buf[uart_rx.wr] = (unsigned char) U2RXREG; //Read the data from buffer
 
            uart_rx.wr = next_data_pos;
 
          }
 
          else{
 
            //When buffer is full, still remove data from register, butthe incoming data is lost
 
            next_data_pos = (unsigned char) U2RXREG; //Read the data from buffer
 
          }
 
      }
 
      _U2RXIF = 0;        //Clear the flag
 
  }
 
*This function reads one byte from the circular buffer.
 
  int uart_read(unsigned char *buf)
 
  {
 
      int next_data_pos;
 
      next_data_pos = pre_rd_cir254buf( uart_rx.wr, uart_rx.rd, MAX_UART_RX_BUF);
 
      //Copy 1 byte when data is available
 
      if (next_data_pos!=255)
 
      {
 
        *buf = uart_rx_buf[uart_rx.rd];    //copy the stored data to buf
 
        uart_rx.rd = next_data_pos;                //update the ptr
 
        return 1;
 
      }
 
      //No data can be copied
 
      else
 
      {
 
          return 0;
 
      }     
 
  }
 
 
 
===I<sup>2</sup>C===
 
 
 
----
 
*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) = (V<sub>dd</sub>-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 acknowledgement from the slave device, ensure to change to idle state.
 
 
 
====open()====
 
*The following structure is used to record whether special bits are needed to be sent.
 
  typedef union{
 
      unsigned char val;
 
      struct{
 
          unsigned START:1;      //start
 
          unsigned RESTART:1;    //restart
 
          unsigned STOP:1;        //stop
 
          unsigned NACK:1;        //not acknowledgment
 
          unsigned :1;
 
          unsigned :1;
 
          unsigned :1;
 
          unsigned :1;   
 
      }bits;
 
  } I2C_STATUS;
 
  static I2C_STATUS i2c_status; 
 
 
 
*Initializing I<sup>2</sup>C with default speed I2C_BRG without interrupts.
 
  void i2c_open(void)
 
  {
 
      //Open i2c if not already opened
 
      if(I2CCONbits.I2CEN == 0)
 
      {
 
          _SI2CIF = 0;        //Clear Slave interrupt
 
          _MI2CIF = 0;        //Clear Master interrupt
 
          _SI2CIE = 0;        //Disable Slave interrupt
 
          _MI2CIE = 0;        //Disable Master interrupt
 
          I2CBRG = I2C_BRG;
 
          I2CCONbits.I2CEN = 1;  //Enable I2C module
 
          i2cIdle();              //I2C bus at idle state, awaiting transimission
 
          i2c_status.val = 0;    //clear status flags
 
      }
 
  }
 
 
 
====ioctl()====
 
*Use this function before read/write to append special bits before or after the data byte.
 
  char i2c_ioctl(unsigned char request, unsigned char* argp)
 
  {
 
      switch(request){
 
          case I2C_SET_STATUS:
 
              i2c_status.val = *argp;
 
              break;
 
          default:
 
              return -1;      //request code not recognised 
 
      }
 
      return 0;
 
  }
 
 
 
====write()====
 
*This function sends an 8-bit data using the I2C protocol.
 
  Mst/Slv    _______ M ____M___ S M ________
 
  SDA (Data)        |S|  data  |A|S|
 
                    |T|        |C|T|
 
                    |A|XXXXXXXX|K|P|
 
*Use ioctl() to select whether a start/restart/stop bit is required.
 
*If slave does not respond after ACK_TIMEOUT, the transmission is considered unsucessful.
 
  int i2c_write(unsigned char *buf)
 
  {
 
      unsigned int count = 0;
 
      if(i2c_status.bits.START)
 
      {
 
          I2CCONbits.SEN = 1;               
 
          Nop();                          //A small delay for hardware to respond
 
          while(I2CCONbits.SEN);          //Wait till Start sequence is completed
 
      }
 
      else if(i2c_status.bits.RESTART)
 
      {
 
          I2CCONbits.RSEN = 1;               
 
          Nop();                          //A small delay for hardware to respond
 
          while(I2CCONbits.RSEN);        //Wait till Start sequence is completed
 
      }
 
      I2CTRN = *buf;                  //Transmit register
 
      while(I2CSTATbits.TBF);        //Wait for transmit buffer to empty
 
      while(I2CSTATbits.ACKSTAT){
 
          if(++count > ACK_TIMEOUT){
 
              //Slave did not acknowledge, byte did not transmit sucessfully,
 
              //send stop bit to reset i2c
 
              I2CCONbits.PEN = 1;
 
              Nop();                          //A small delay for hardware to respond
 
              while(I2CCONbits.PEN);          //Wait till stop sequence is completed
 
              i2cIdle();
 
              return 0;
 
          }
 
      }
 
      i2cIdle();
 
      if(i2c_status.bits.STOP)
 
      {
 
          I2CCONbits.PEN = 1;
 
          Nop();                          //A small delay for hardware to respond
 
          while(I2CCONbits.PEN);          //Wait till stop sequence is completed
 
          i2cIdle();
 
      }
 
      i2c_status.val = 0;            //Clear status
 
      return 1;
 
  }
 
 
 
====read()====
 
*This function reads 1 byte from slave using the I2C protocol.
 
  Mst/Slv    ____ ___S____ M M _____   
 
  SDA (Data)      |  data  |A|S|
 
                  |        |C|T|
 
                  |XXXXXXXX|K|P|
 
*Use ioctl() to select whether an ACK/NACK and/or STOP bit is needed to be sent.
 
  int i2c_read(unsigned char *buf)
 
  {
 
      I2CCONbits.RCEN = 1;                    //Enable Receive
 
      while(I2CCONbits.RCEN);
 
      I2CSTATbits.I2COV = 0;                  //Clear receive overflow
 
      *buf = (unsigned char) I2CRCV;          //Access the receive buffer
 
      I2CCONbits.ACKDT = (i2c_status.bits.NACK)? 1 : 0;
 
      I2CCONbits.ACKEN = 1;      //Send Acknowledgement/Not Acknowledgement
 
      i2cIdle();                  //I2C bus at idle state, awaiting transimission
 
      if(i2c_status.bits.STOP)
 
      {
 
          I2CCONbits.PEN = 1;
 
          Nop();                          //A small delay for hardware to respond
 
          while(I2CCONbits.PEN);          //Wait till stop sequence is completed
 
          i2cIdle();
 
      }
 
      i2c_status.val = 0;            //Clear status
 
      return 1;
 
  }
 
 
 
====Example====
 
  Mst/Slv    _______ M ___M___ M S ____M___ S M ___M___ M S ___S____ M ___S____ M M _____
 
  SDA (Data)        |S|      | |A|        |A|R|      | |A|        |A|        |N|S|
 
                    |T|address|W|C|channelA|C|E|address|R|C| Data H |C| Data L |A|T|
 
                    |A|1001111|0|K|00010010|K|S|1001111|1|K|10101010|K|10XXXXXX|K|P|
 
 
 
  /*
 
    * Send start bit, slave address (Write Mode)
 
    */
 
  status = I2C_START;
 
  i2c_ioctl(I2C_SET_STATUS, &status);
 
  data = (unsigned char) I2C_SLAVE_ADDR;
 
  i2c_write(&data);
 
  /*
 
    * Send control byte: Channel select
 
    */
 
  data = (unsigned char) ctrl_byte;
 
  i2c_write(&data);
 
  /*
 
    * Send restart bit, slave address (Read Mode)
 
    */
 
  status = I2C_RESTART;
 
  i2c_ioctl(I2C_SET_STATUS, &status);
 
  data = (unsigned char) (I2C_SLAVE_ADDR|0x01);
 
  i2c_write(&data);
 
  /*
 
    * Receive High Byte with Acknowledgment
 
    */
 
  i2c_read(&data);
 
  usr_data.high = (unsigned char) data;
 
  /*
 
    * Receive Low Byte with Not Acknowledgment and stop bit
 
    */
 
  status = I2C_NACK | I2C_STOP;
 
  i2c_ioctl(I2C_SET_STATUS, &status);
 
  i2c_read(&data);
 
  usr_data.low = (unsigned char) data;
 
 
 
===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.
 
====open()====
 
*The following variables are required.
 
  unsigned int adc_buf[ADC_MAX_CH];  //Store most updated data
 
  volatile unsigned int* ADC16Ptr = &ADCBUF0; //Pointer to ADC register buffer,
 
  unsigned char adc_ch_select = 0;  //Pointer to channel to be read from
 
  unsigned char adc_data_ready = 0;  //Indicate if RAM data is ready for output
 
*Configuration is highlighted below.
 
**Interrupt: The ADC module will be set to interrupt when the specified channels are updated.
 
**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.
 
**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).
 
**Reference Voltage for S/H: Only MUX A is used. By default, the negative reference voltage of the S/H is connected to V<sub>REF-</sub>.
 
**Settings for ADC Operation: For 200kbps operation, the voltage references for the ADC voltage are connected to V<sub>REF+</sub> and V<sub>REF-</sub>. Scan input is enabled, and the module will generate an interrupt when all selected channels have been scanned.
 
**Sampling Rate: T<sub>AD</sub> refers to the time unit for the ADC clock. To configure the ADC module at 200kbps, the minimum sampling time of 1T<sub>AD</sub> = 334ns is required. ADCS<5:0> in ADCON3 register is used to set the time, which is given by:
 
      ADCS<5:0> = 2(T<sub>AD</sub>/T<sub>CY</sub>)-1
 
                = 2(334e-9/33.34e-9)-1
 
                = 19
 
 
 
  char adc_open(int flags)
 
  {
 
      // Configure interrupt
 
      _ADIF = 0;                          //clear ADC interrupt flag
 
      _ADIE = 1;                          //enable adc interrupt
 
    // Configure analog i/o 
 
    _TRISB0 = 1;
 
    _TRISB1 = 1;   
 
    ADPCFG = 0xFFFC;                    //Enable AN0 (Vref+) and AN1 (Vref-)
 
    // Configure scan input channels   
 
    ADCSSL = 0x0003;    //0 => Skip, 1 => Scan
 
    // Configure CH0 Sample and Hold for 200kbps
 
    //  +-- Use MUX A only
 
    //  +-- Set CH0 S/H -ve to VRef-
 
    ADCHSbits.CH0NA = 0;
 
    // ADCCON3:
 
    //  +--Auto Sample Time = 1TAD
 
    //  +--A/D Conversion Clock Source = system clock
 
    //  +--A/D Conversion Clock Select ADCS<5:0>= 2(TAD/TCY)-1
 
    //      200kbps(Sampling frequency)
 
    ADCON3bits.SAMC = ADC_ACQ_TIME;    //1TAD for sampling time
 
    ADCON3bits.ADRC = 0;                //Use system clock
 
    ADCON3bits.ADCS = ADC_ADCS;        //each conversion requires 14TAD
 
    // ADCCON2:
 
    //  +--Default: Use MUX A, No splitting of Buffer
 
    //  +--Voltage Reference Configuration Vref+ and Vref-
 
    //  +--Scan Input Selections
 
    //  +--5 samples between interrupt
 
    ADCON2bits.VCFG = 3;                //External Vref+, Vref-
 
    ADCON2bits.CSCNA = 1;              //Scan input
 
    ADCON2bits.SMPI = 1;                //take 2 samples (one sample per channel) per interrupt
 
    // ADCCON1:
 
    //  +--Default: continue in idle mode, integer format
 
    //  +--Enable ADC, Conversion Trigger Source Auto, Auto sampling on
 
    ADCON1bits.FORM = 0;                //[0:integer]; [2 fractional]; [3 siged fractional]
 
    ADCON1bits.SSRC = 7;                //auto covert, using internal clock source
 
    ADCON1bits.ASAM = 1;                //auto setting of SAMP bit
 
    ADCON1bits.ADON = 1;                //Turn on module
 
    return 0;
 
  }
 
 
 
====read()====
 
*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){
 
      unsigned int channel = 0;
 
      unsigned int buffer = 0;
 
      for (; channel<ADC_MAX_CH; channel++)
 
      {
 
        if(select(channel))      //Check if channel has been selected
 
        {
 
            adc_buf[channel] = ADC16Ptr[buffer];    //Copy data to adc_buf
 
            buffer++;
 
        }
 
      }
 
      adc_data_ready = 1;
 
      _ADIF = 0;  //Clear adc interrupt
 
  }
 
 
 
  static unsigned char select(unsigned char ch)
 
  {
 
      unsigned int mask;
 
      mask = 0x0001 << ch;
 
      if(ADCSSL & mask)
 
          return 1;
 
      return 0;
 
  }
 
*User can read from the buffer at anytime to get the most updated analog values.
 
  int adc_read(unsigned int* buf, int count)
 
  {
 
      if(adc_data_ready == 1)
 
      {
 
        int num_channel = count/2;                  //number of channels to read
 
        unsigned char channel = adc_ch_select;    //index for adc_buf
 
        int i = 0;                                  //index for buf
 
        while(i<num_channel && channel<ADC_MAX_CH)
 
        {
 
            //Loop only for specified number of channel or all channels
 
            buf[i++] = adc_buf[channel++];      //use data in local buffer
 
            while(select(channel)==0)
 
            {  //increment to next valid channel
 
              channel++;                 
 
              if(channel >= ADC_MAX_CH) break;
 
            }
 
        }
 
        return 2*i;
 
      }
 
      return -1;
 
  }
 
 
 
====ioctl()====
 
*This function is used to add or remove channels from the ADC scanning process.
 
  char adc_ioctl(unsigned char request, unsigned char* argp)
 
  {
 
      switch(request)
 
      {
 
          case ADC_ADD_CH:
 
              //ADD channels to current set==========================
 
              cli();                      //Disable global interrupt
 
              if(select(argp[0]) == 0){  //If channel not in scan list
 
                  adcAdd(argp[0]);            //Add individual channel to scan list
 
                  adc_data_ready = 0;        //First data not ready yet, until interrupt occurs
 
              }
 
              adc_ch_select = argp[0];    //Select current channel for reading
 
              sti();                      //Enable global interrupt
 
              break;
 
          case ADC_RM_CH:
 
              //REMOVE channels from current set==========================
 
              cli();                  //Disable global interrupt
 
              if(select(argp[0])){    //If channel in scan list     
 
                  adcRm(argp[0]);            //Remove individual channel
 
                  adc_ch_select = 0;          //Reset to AN0
 
              }
 
              sti();                  //Enable global interrupt
 
              break;
 
          default:
 
              return -1;      //request code not recognised 
 
      }
 
      return 0;
 
  }
 
*Channels may be added or removed by changing _TRISBX, ADPCFG, ADCSSL and ADCON2bits.SMPI.
 
  void adc_add_ch(unsigned char ch){
 
      unsigned int mask;
 
      mask = 0x0001 << ch;
 
      TRISB = TRISB | mask;
 
      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;
 
====lseek()====
 
*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
 
 
 
===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 ''f''<sub>PWM</sub> is given by:
 
        f<sub>PWM</sub> = f<sub>CY</sub>/(Prescale*10<sup>rlog(2)</sup>)
 
  
{| border="1" cellspacing="0" cellpadding="5"
+
[[category:projects]]
|+ Table 6.3 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
 
|-
 
|}
 
 
 
====open()====
 
*A timer (either Timer 2 or 3) is needed to determine the pwm period. The following code uses timer 2 for all 8 channels.
 
  void pwm_open(void){
 
    OC1CON = 0; OC2CON = 0; //Disable all output compare modules
 
    OC3CON = 0; OC4CON = 0;
 
    OC5CON = 0; OC6CON = 0;
 
    OC7CON = 0; OC8CON = 0;
 
    //============================================================
 
    TMR2 = 0; // Clear register
 
    PR2 = 0xFFFF; // Set to Maximum
 
    //============================================================
 
    _T2IP = 7; // Set priority level to 7 (7 Highest)
 
    _T2IF = 0; // Clear interrupt flag
 
    _T2IE = 1; // Enable interrupts
 
    //============================================================
 
    T2CONbits.TCS = 0; // Use internal clock source
 
    T2CONbits.TCKPS = 0; // Prescale Select 1:1
 
    //============================================================
 
    T2CONbits.TON = 1; // Start the timer
 
  }
 
  void _ISR _T2Interrupt(void){
 
    _T2IF = 0; // Clear interrupt flag
 
  }
 
 
 
====ioctl()====
 
*User should select the channel and set the pwm period using the functions below before issuing the duty cycle:
 
  char pwm_ioctl(unsigned char request, unsigned long* argp){
 
    unsigned int value;
 
    unsigned char mask;
 
    switch(request){
 
      case PWM_SET_PERIOD:
 
        return setPeriodNPrescale(argp[0]);
 
      case PWM_SELECT_CH:
 
        pwm_channel = argp[0];
 
        mask = 0x01 << pwm_channel;
 
        pwm_status = pwm_status | mask;
 
            return 0;
 
      default:
 
            return -1;
 
    }
 
  }
 
  char setPeriodNPrescale(unsigned long value_ns){
 
    unsigned long ans;
 
    unsigned long long numerator = (unsigned long long)value_ns*SYSTEM_FREQ_MHZ;
 
    unsigned char index= -1;
 
    unsigned long denominator;
 
    //-------------------------------------------------
 
    do{
 
        denominator = (unsigned long)1000*pwm_prescale[++index];
 
        ans = (unsigned long)(((long double)numerator/denominator) + 0.5) - 1; //round to nearest int
 
    } while(ans > 0x0000FFFF && index < 3);
 
    //-------------------------------------------------
 
    if(ans > 0x0000FFFF)
 
        return -1;
 
    //-------------------------------------------------
 
    T2CONbits.TON = 0; // Turn off the timer
 
    T2CONbits.TCKPS = index; // Change prescale factor
 
    PR2 = (unsigned int) ans; // Set to Maximum
 
    T2CONbits.TON = 1; // Turn on the timer
 
    //-------------------------------------------------
 
    return 0;
 
  }
 
 
 
====write()====
 
*User can change the duty cycle using the following functions
 
  int pwm_write(unsigned long* buf){
 
    if((pwm_status & (0x01 << pwm_channel)) == 0){
 
        return -1; //Channel has not been enabled
 
    }
 
    switch(pwm_channel){
 
        case 0:
 
            OC1RS = calcDCycle(buf[0]); OC1R = OC1RS;
 
            OC1CONbits.OCM = 6; //Simple PWM, Fault pin disabled
 
            break;
 
        case 1:
 
            OC2RS = calcDCycle(buf[0]); OC2R = OC2RS;
 
            OC2CONbits.OCM = 6; //Simple PWM, Fault pin disabled
 
            break;
 
        ...
 
        case 7:
 
            OC8RS = calcDCycle(buf[0]); OC8R = OC8RS;
 
            OC8CONbits.OCM = 6; //Simple PWM, Fault pin disabled
 
            break;
 
        default:
 
            return -1;
 
    }
 
    return 4;
 
}
 
  unsigned int calcDCycle(unsigned long value_ns){
 
    unsigned long long numerator = (unsigned long long)value_ns*SYSTEM_FREQ_MHZ;
 
    unsigned int index = T2CONbits.TCKPS;
 
    unsigned long denominator = (unsigned long)1000*pwm_prescale[index];
 
    return (unsigned int)(((long double)numerator/denominator) + 0.5) - 1; //round to nearest int
 
  }
 
 
 
====Propagration Delay====
 
*PWM channels sharing the same timer will have their PWM signals synchronised (i.e. the HIGH state of the duty cycle are all triggered together).
 
*To introduced delay to the PWM signals, the signal from selected channels may be made to pass through a series of inverters (e.g. 74HC14D). This adds propagation delay to the signal.
 
*However, as propagration delay of logic gates depends on applied voltage, temperature and load capacitance, the accuracy is low and performance is poor. For accurate delay, delay lines may be used, but they are expensive.
 
 
 
{| border="1" cellspacing="0" cellpadding="5"
 
|+ Table 6.4 Propagation Delay of [http://www.nxp.com/acrobat_download/datasheets/74HC_HCT14_3.pdf Philips 74HC14D]<sup>[1], [2]</sup>
 
! !! 3.3V !! !! !! 5.0V !! !!
 
|-
 
! Number of Gates !! A !! B !! C !! A !! B !! C
 
|-
 
| 2
 
| 21ns (10.5)|| 23ns (11.5)|| 22ns (11.0)
 
| 15ns (7.5)|| 14ns (7.0)|| 14ns (7.0)
 
|-
 
| 4
 
| 45ns (11.3)|| 46ns (11.5)|| 46ns (11.5)
 
| 30ns (7.5)|| 30ns (7.5)|| 30ns (7.5)
 
|-
 
| 6
 
| 69ns (11.5)|| 70ns (11.7)|| 72ns (12.0)
 
| 45ns (7.5)|| 46ns (7.7)|| 47ns (7.8)
 
|-
 
|}
 
[1] Data in specification for 4.5V: Typical 15ns, Maximum 25ns<br>
 
[2] Data in specification for 6.0V: Typical 12ns, Maximum 21ns
 
 
 
===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<sup>-15</sup> inclusive.
 
**Bit<15> is a signed bit, positive = 0, negative = 1.
 
**Bit<14:0> are the exponent bits ''e''.
 
**Positive value = 1 - 2<sup>-15</sup>*(32768 - ''e'')
 
**Negative value = 0 - 2<sup>-15</sup>*(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<sup>-15</sup>]
 
**Floating point values can be converted to Fractional values using: '''fr = Float2Fract(fo);''' or '''fr = Q15(fo);''' for fo = [-1, 1-2<sup>-15</sup>]
 
**Float2Fract() is same as Q15(), except having saturation control. When +ve >= 1, answer = 2<sup>15</sup>-1 = 32767 (0x7FFF). When -ve < -1, answer = -2<sup>15</sup> = -32767 (0x8000)
 
 
 
===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.
 
 
 
 
 
{| border="1" cellspacing="0" cellpadding="5"
 
|+ Table 7.1 Free bootloaders for dsPIC
 
! Developer
 
! Source
 
! Platform
 
! User Guide
 
! Remarks
 
|- valign="top"
 
| [http://www.ingenia-cat.com/index.php?lang=en ingenia]
 
| [http://www.ingenia-cat.com/download/iBL.s Assembly]
 
| [http://www.ingenia-cat.com/download/ingeniadsPICbootloader1.1.zip Windows]
 
| [http://www.ingenia-cat.com/reference/pdf/iBL.UG.V1.2.pdf pdf]
 
|
 
*Works for all dsPIC supporting RTSP
 
*Auto baudrate detection
 
*Use about 1.15% of the flash memory space (0xAFFF-0xAE00)/(0xAFFF-0x0100)
 
*Development of Linux platform is underway
 
*Modification of code for dsPIC30F5011 is successful
 
|-valign="top"
 
| [http://www.etc.ugal.ro/cchiculita/software/picbootloader.htm Tiny]
 
| [http://www.etc.ugal.ro/cchiculita/software/tinybld191.zip Assembly]
 
| Windows
 
| [http://www.etc.ugal.ro/cchiculita/software/tinybldusage.htm Web]
 
|
 
*By default, only supports 601X, 601X, 401X, 2010
 
*Smaller code size than ingenia, but not as easy to modify
 
|-valign="top"
 
| [http://www.via.si/software/dsPIC_bootloader/ Elektronika]
 
| [http://www.via.si/software/dsPIC_bootloader/data/ Hex]
 
| Windows
 
| [http://www.via.si/software/dsPIC_bootloader/data/README.txt txt]
 
|
 
*Only works for dsPIC30F6014 serial port UART2 at baudrate 57600
 
|-
 
|}
 
 
 
===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 [http://www.ingenia-cat.com/download/iBL.s 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 Multi-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 [http://www.rxtx.org/ 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:
 
#Can be used on both Linux and Windows platforms.
 
#Adjustable baudrate (9600bps to 57600bps).
 
#Support programming of dsPIC30F5011 and dsPIC33FJ128GP306 devices (Developers may add your devices).
 
#Protection against overwriting bootloader codes on devices.
 
#Detection if application program does not have its reset() at user's code start address.
 
#Reprogramming can be done without powering down the target board, provided the user's program is compliant to that stated below.
 
#Target board will run the user's program after programming is done.
 
#Can be used with USB-Serial Cables. Below is a list of tested cable:
 
::[http://www.prolific.com.tw/eng/Products.asp?ID=59 Prolific PL-2303 USB to Serial Bridge Controller]: [http://www.prolific.com.tw/eng/downloads.asp?ID=31 Driver download]
 
 
 
===Special Consideration===
 
*The bootloader assumes that the user program starts at address 0x100. This is usually the case, but there are always exceptions.
 
*To ensure that the user program always starts at address 0x100, you can create a customized linker script and customized reset() function as follows:
 
:*Copy and modify the file named "crt0.s" from the directory "C:\Program Files\Microchip\MPLAB C30\src\pic30" to the project directory and include it.
 
    .section .reset, code      //previously .section .libc, code
 
:*Copy and modify the linkerscript for the device (e.g. p30f5011.gld) to the project directory and include it.
 
  .text __CODE_BASE :
 
  {
 
      *(.reset);              //<-insert this line here
 
      *(.handle);
 
      *(.libc) *(.libm) *(.libdsp);  /* keep together in this order */
 
      *(.lib*);
 
      *(.text);
 
  } >program
 
 
 
===Communication Protocol===
 
 
 
          +-------------------+            +-------------------+----------------+
 
          |  dsPicProgrammer  |            |  dsPicBootloader  | User's Program |
 
          +-------------------+            +-------------------+----------------+
 
          |      PC          |            |            Target dsPic          |
 
          +-------------------+            +------------------------------------+
 
          |    COM PORT      |=============|                UART              |
 
          +-------------------+            +------------------------------------+
 
 
 
* '''Stage 1: User's Configuation'''
 
**Select a COM port channel
 
**Select a baudrate
 
**Select the user hex file
 
          java -jar dsPicProgrammer.jar COM1 19200 foo.hex
 
* '''Stage 2: Resetting Target Device'''
 
**dsPicProgrammer sends a Break character (pull UART-TX to low logic, which is normally high).
 
**User's program on dsPic detects the break character and reset the chip
 
::NOTE: The user's program is expected to have the following code in order to enable this function. Otherwise, the target board must be restarted manually.
 
  void _ISR _U2RXInterrupt(void)
 
  {
 
      //No Framming error
 
      if( U2STAbits.FERR == 0)
 
      {
 
          //Normal procedure
 
      }
 
      //Framming error
 
      else
 
      {
 
          if ( U2STAbits.URXDA ){
 
              unsigned char data;
 
              data = (unsigned char) U2RXREG;
 
              if(data == 0x00){
 
                  // A break char has been received:
 
                  //  U2RX has been pulled to zero for more than 13 bits
 
                  //  This is used to reboot the pic
 
                  mdelay(800);    //wait for break character to clear
 
                  asm("reset");  //software reset
 
              }
 
          }       
 
      }
 
      _U2RXIF = 0;        //Clear the flag
 
  }
 
* '''Stage 3: Entering Ingenia's Protocol'''
 
** Transmission is conducted in 8N1, i.e. 8-bit, no parity, 1 stop-bit
 
** Communication Protocol is reviewed in [http://www.ingenia-cat.com/reference/pdf/iBL.UG.V1.2.pdf 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).
 
::#Autobaud rate detection: dsPicProgrammer continuously sends a character "U" [0x55] via COM port and waits for an acknowledgment character "U", [ACK] = [0x55]
 
::#Version Control: dsPicProgrammer sends the command character [0x03]. On success, dsPicProgrammer receives 3 characters i) Major Version ii) Minor Version iii) Acknowledgment [0x55]
 
::#Device ID Monitoring: dsPicProgrammer sends the read command character [0x01] + 24-bit address [High][Medium][Low] (0xFF0000). Then, it receives 4-byte data [High][Medium][Low][ACK]
 
::#Load the user hex file and check integrity
 
::#Start Programming: dsPicProgrammer issues the 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) and receives [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)
 
* '''Stage 4: Goto User's Program'''
 
**dsPicProgrammer sends the goto user code command [0x0F]
 
 
 
 
 
==USB-RS232 Bridge==
 
 
 
*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 [http://www.prolific.com.tw/eng/downloads.asp?ID=31 Prolific] and [http://www.ftdichip.com/Drivers/VCP.htm 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 [http://java.sun.com/products/javacomm/ JavaComm API] (javax.comm) and/or [http://www.rxtx.org/ RXTX] to drive the COM port.
 
#Modified the bootloader program on PC to support USB communication. e.g. using [http://jusb.sourceforge.net/ jUSB] and [http://javax-usb.org/ 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 Chipset===
 
*FT232RL communicates with PC via USB to provide 1 UART channel.
 
*Datasheet can be downloaded [http://www.ftdichip.com/Documents/DataSheets/DS_FT232R.pdf here].
 
**Refer to Fig. 11 (Page 19) for Bus Powered Configuration.
 
**Refer to Fig. 16 (Page 24) for for UART TTL-level Receive [RXD -> 1], Transmit [TXD -> 4], Transmit Enable [CBUS2/TXDEN -> 3]. Omit Receive Enable [CBUS3/PWREN#] and use [CBUS2/TXDEN -> 2]
 
**Refer to Fig. 15 (Page 23) for LED Configuration: [CBUS0/TXLED#] and [CBUS1/RXLED#]
 
*Virtual COM Port Drivers can be downloaded [http://www.ftdichip.com/Drivers/VCP.htm here].
 
 
 
 
 
==Programming the Device==
 
 
 
===Requirements===
 
*Hardware
 
#PC with COM port (Windows XP Installed for MPLAB)
 
#ICD2 Programmer
 
#Target Board
 
#5V Power Supply
 
 
 
*Software
 
#[http://ww1.microchip.com/downloads/en/DeviceDoc/MP750.zip MPLAB IDE v7.50 or higher]
 
#[http://chungyan5.no-ip.org/websvn/listing.php dsPicProgrammer] ('''dsPicProgrammer.jar''')
 
#[http://users.frii.com/jarvi/rxtx/download.html RXTX driver]
 
 
 
*Files
 
#[http://chungyan5.no-ip.org/websvn/listing.php dsPicBootloader] ('''bl_5011.hex'''). Original assembly code by ingenia can be downloaded from [http://www.ingenia-cat.com/download/iBL.s here].
 
#Application hex file (e.g. '''app.hex''')
 
 
 
===Loading Bootloader (Once only)===
 
{|border="1" cellspacing="0" cellpadding="5"
 
|+ Table 9.1 Loading Bootloader
 
! Step !! Remarks
 
|-valign="top"
 
| Install [http://ww1.microchip.com/downloads/en/DeviceDoc/MP750.zip MPLAB IDE] ||
 
*Do '''NOT''' connect ICD 2 (via USB) to PC
 
*Execute '''MPLAB vX.XX Install.exe'''
 
|-valign="top"
 
| Install USB Driver ||
 
*Follow the instruction in (C:\Program Files\Microchip\MPLAB IDE\ICD2\Drivers\Ddicd2.htm)
 
|-valign="top"
 
| Select Target Chip ||
 
*Run MPLAB IDE on PC
 
*Select: Configure>Select Devices...
 
*Choose dsPIC30F5011
 
|-valign="top"
 
| Target <-> ICD 2  ||
 
*Use six pin cable. Beware of the pin assignments. Only pin 1 - 5 should be used.
 
*Place Jumper on target board (if any). The Jumper connects target V<sub>cc</sub> to ICD 2.
 
*Do '''NOT''' power-up the target.
 
|-valign="top"
 
| ICD 2 <-> PC ||
 
*Plug-in ICD 2 to PC via USB cable
 
*Power-up the target.
 
*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
 
*If you have not connected and powered up the target, you might see Warnings on invalid device IDs, and/or running self tests.
 
*See results of self test if necessary: Programmer>Settings, Status Tab. Refer to [http://ww1.microchip.com/downloads/en/DeviceDoc/51331B.pdf ICD2 User's Guide] Chapter 7.
 
|-valign="top"
 
| Load Bootloader ||
 
*Select: File>Import...
 
*Select '''bl_5011.hex'''
 
|-valign="top"
 
| Start Programming ||
 
*Select: Programmer>Program
 
|-valign="top"
 
| Finishing ||
 
*Power-down the Taget
 
*Select: Programmer>Select Programmer>None
 
*Unplug USB cable
 
|-
 
|}
 
 
 
===Loading Application===
 
{|border="1" cellspacing="0" cellpadding="5"
 
|+ Table 9.2 Loading Application File
 
! Step !! Remarks
 
|-valign="top"
 
| Install RXTX ||
 
*For Windows User:
 
**copy RXTXcomm.jar to \jre\lib\ext (under java)
 
**copy rxtxSerial.dll to \jre\bin
 
*For Linux User:
 
**copy RXTXcomm.jar to /jre/lib/ext (under java)
 
**copy librxtxSerial.so to /jre/lib/[machine type] (i386 for instance)
 
|-valign="top"
 
| Connect target board ||
 
*For Windows User:
 
**connect to COM1 (or other usable port)
 
*For Linux User:
 
**connect to ttyS0 (or other usable port)
 
|-valign="top"
 
| Open a console window ||
 
*In Windows, Start>Run, and type cmd.
 
|-valign="top"
 
| Start Programming ||
 
*Change to the directory containing dsPicProgrammer.jar
 
*Execute dsPicProgrammer.jar
 
**For Windows User: java -jar dsPicProgrammer.jar COM1 57600 Y:\foo2\app.hex
 
**For Linux User: java -jar dsPicProgrammer.jar /dev/ttyS0 57600 Y:/foo2/app.hex
 
|-
 
|}
 
 
 
 
 
==Remote Access==
 
*At the moment, local devices (e.g. EEPROM, ADC, DAC, etc.) can only be accessed locally through POSIX functions such as open(), read(), write(), ioctl().
 
*However, a client may need to access these devices on a remote server. This section reviews the background and gives some ideas on its possible implementation.
 
 
 
===Requirements===
 
*A remote file access protocol, to transfer "files" (i.e. device's data) such as:
 
#[http://en.wikipedia.org/wiki/FTP File Transfer Protocol] (FTP): Required files are copied from sever to client for manipulation
 
#[http://en.wikipedia.org/wiki/Remote_Shell Remote Shell] (RSH): Required files are copied from sever to client for manipulation
 
#[http://en.wikipedia.org/wiki/Network_File_System_%28Sun%29 Network File System] (NFS): Required files are manipulated on sever
 
*An API to access files using a selected protocol, such as:
 
#[http://www.die.net/doc/linux/man/man2/lam_rfposix.2.html lam_rfposix]: A POSIX-like remote file service for Local Area Multicomputer
 
#API employed by VxWorks: [http://en.wikipedia.org/wiki/VxWorks VxWorks] is a Unix-like real-time operating system, commonly used for embedded systems.
 
 
 
===API Reference for VxWorks===
 
*Reference:
 
**[http://www.windriver.com/vxworks/ VxWorks Official Website]
 
**[http://www-cdfonline.fnal.gov/daq/commercial/ OS Libraries API Reference]
 
*Related Libraies
 
**netDrv (netDrv.h): an API using FTP or RSH
 
**nfsDrv (nfsDrv.h): an API using NFS
 
 
 
 
 
==Conversion to dsPIC33F Devices==
 
*This section discusses the conversion required from dsPIC30F5011 to dsPIC33FJ128GP306.
 
*Refer to official document [http://ww1.microchip.com/downloads/en/DeviceDoc/70172A.pdf dsPIC30F to dsPIC33F Conversion Guidelines] (DS70172A).
 
*Note that this section does not mainly intend to introduce the new functionalities of dsPIC33F devices. It only serves the purpose to summarise the major (if not minimum) changes required to port the setup of dsPIC30 to dsPIC33 devices.
 
 
 
===Hardware===
 
*dsPIC33 operates at voltage of 3.3V. A voltage regulator, such as [http://www.national.com/ds.cgi/LM/LM3940.pdf LM3940] can be used to convert 5V supply to 3.3V.
 
*A 1uF capacitor has to be placed at pin 56 (previously V<sub>SS</sub>, now V<sub>DDCORE</sub>).
 
 
 
===Software===
 
 
 
====Configuration Bits====
 
 
 
----
 
*dsPIC33 can operate at 40MIPs at maximum. To configure the device using internal FRC, replace the configuration bits setting as follows:
 
  _FOSCSEL(FNOSC_FRCPLL);  // FRC Oscillator with PLL
 
  _FOSC(FCKSM_CSDCMD & OSCIOFNC_ON  & POSCMD_NONE); 
 
                            // Clock Switching and Fail Safe Clock Monitor is disabled
 
                            // OSC2 Pin Function: OSC2(RC15) as Digital IO
 
                            // Primary Oscillator Mode: Disabled
 
  _FWDT(FWDTEN_OFF);      // Watchdog Timer Enabled/disabled by user software
 
*Configure on-chip PLL at runtime as follows (at start of main function):
 
  _PLLDIV = 38;            // M=40: PLL Feedback Divisor bits
 
  CLKDIV = 0;              // N1=2: PLL VCO Output Divider Select bits
 
                            // N2=2: PLL Phase Detector Input Divider bits
 
  OSCTUN = 22;              // Tune FRC oscillator, if FRC is used;
 
                            // 0: Center frequency (7.37 MHz nominal)
 
                            // 22: +8.25% (7.98 MHz)
 
  RCONbits.SWDTEN = 0;      // Disable Watch Dog Timer
 
  while(OSCCONbits.LOCK != 1); // Wait for PLL to lock
 
 
 
====UART====
 
 
 
----
 
*No change is required.
 
 
 
====I2C====
 
 
 
----
 
*dsPIC33 supports upto 2 I<sup>2</sup>C devices. As a result, replace all I<sup>2</sup>C related registers with xxI2Cyy to xxI2C'''1'''yy. For examples:
 
  _SI2C1IF = 0; //Clear Slave interrupt
 
  _MI2C1IF = 0; //Clear Master interrupt
 
  _SI2C1IE = 0; //Disable Slave interrupt
 
  _MI2C1IE = 0; //Disable Master interrupt
 
  I2C1BRG = I2C_BRG; // Configure Baud rate
 
  I2C1CONbits.I2CEN = 1;
 
  ...
 
  etc.
 
 
 
====ADC====
 
 
 
----
 
*The ADC in dsPic33 is significantly different from that in dsPic30. Specifically, ADC in dsPic33 uses DMA to buffer the adc data. Replace the open, interrupt routine, add and remove codes as follows:
 
 
 
  unsigned int adc_bufA[ADC_MAX_CH] __attribute__((space(dma),aligned(256)));
 
  unsigned int adc_bufB[ADC_MAX_CH] __attribute__((space(dma),aligned(256)));
 
  unsigned int* ADC16Ptr;            //Pointer to ADC register buffer,
 
  unsigned char adc_ch_select = 0;    //Pointer to channel to be read from
 
  unsigned char adc_data_ready = 0;  //Indicate if RAM data is ready for output
 
  unsigned int which_dma = 0;        //indicate which adc_buf to be used
 
 
 
  void adc_open(void)
 
  {
 
      // Configure interrupt
 
      _AD1IF = 0;              //clear ADC interrupt flag
 
      _AD1IE = 0;              //disable adc interrupt
 
      AD1CHSbits.CH0NA = 0;
 
      // Configure analog i/o 
 
      _TRISB0 = 1;
 
      _TRISB1 = 1;   
 
      AD1PCFG = 0xFFFC;        //Enable AN0 (Vref+) and AN1 (Vref-)
 
      AD1PCFGH = 0xFFFF;      //AN16-AN31: Disabled
 
      // Configure scan input channels   
 
      AD1CSSL = 0x0003;    //0 => Skip, 1 => Scan
 
      AD1CSSH = 0x0000;    //Skipping AN16-AN31
 
      // ADCCON4:
 
      AD1CON4bits.DMABL = 0;    // Each buffer contains 1 word
 
      // ADCCON3:
 
      AD1CON3bits.SAMC = 1; //1TAD for sampling time
 
      AD1CON3bits.ADRC = 0;            //Use system clock
 
      AD1CON3bits.ADCS = ADC_ADCS;    //each conversion requires 14TAD
 
      // ADCCON2:
 
      AD1CON2bits.VCFG = 3;    //External Vref+, Vref-
 
      AD1CON2bits.CSCNA = 1;  //Scan input
 
      AD1CON2bits.SMPI = 1;    //2 channels are scanned
 
      // ADCCON1:
 
      AD1CON1bits.FORM = 0;        //[0:integer]; [2 fractional]; [3 siged fractional]
 
      AD1CON1bits.SSRC = 7;        //auto covert, using internal clock source
 
      AD1CON1bits.ASAM = 1;        //auto setting of SAMP bit
 
      AD1CON1bits.AD12B = 1;      //12-bit, 1-channel ADC operation
 
      AD1CON1bits.ADDMABM = 0;    // DMA buffers are built in scatter/gather mode
 
      AD1CON1bits.ADON = 1;        // Turn on the A/D converter
 
      // DMA0 Configuration:
 
      DMA0CONbits.AMODE = 2;      // Configure DMA for Peripheral indirect mode
 
      DMA0CONbits.MODE  = 2;      // Configure DMA for Continuous Ping-Pong mode
 
      DMA0PAD=(int)&ADC1BUF0;   
 
      DMA0CNT = 1;                // generate dma interrupt every 2 samples
 
                                  // same as SMPI because only 1 dma buffer per channel       
 
      DMA0REQ = 13;              // Select ADC1 as DMA Request source
 
      DMA0STA = __builtin_dmaoffset(adc_bufA);   
 
      DMA0STB = __builtin_dmaoffset(adc_bufB);
 
      _DMA0IF = 0;                // Clear the DMA interrupt flag bit
 
      _DMA0IE = 1;                // Set the DMA interrupt enable bit
 
      DMA0CONbits.CHEN=1;        // Enable DMA
 
  }
 
 
 
  void _ISR _DMA0Interrupt(void)
 
  {
 
      ADC16Ptr = (which_dma == 0)? adc_bufA : adc_bufB;  //Update pointer
 
      adc_data_ready = 1;
 
      which_dma ^= 1;                                    //Next buffer to be used
 
      _DMA0IF = 0;                                        //Clear the DMA0 Interrupt Flag
 
  }
 
 
 
  static void adcAdd(unsigned char ch){
 
      unsigned int mask;
 
      mask = 0x0001 << ch;
 
      TRISB = TRISB | mask;
 
      AD1CSSL = AD1CSSL | mask;     
 
      AD1PCFG = ~AD1CSSL;
 
      AD1CON2bits.SMPI++;  //take one more sample per interrupt
 
      DMA0CNT++;
 
  }
 
 
 
  static void adcRm(unsigned char ch){
 
      unsigned int mask;
 
      mask = 0x0001 << ch;
 
      AD1PCFG = AD1PCFG | mask;
 
      AD1CSSL = ~AD1PCFG;
 
      AD1CON2bits.SMPI--;  //take one less sample per interrupt
 
      DMA0CNT--;
 
  }
 
 
 
====EEPROM====
 
 
 
----
 
*There is no EEPROM in dsPIC33 devices. Please consider to use an external EEPROM using I<sup>2</sup>C communication.
 
 
 
====Simple PWM====
 
 
 
----
 
*No change is required.
 
 
 
===Memory Map for dsPIC33FJ128GP306===
 
{| border="1" cellspacing="0" cellpadding="5"
 
|+ Table 11.1 Memory Location
 
! Type !! Start Address !! End Address !! Size
 
|-valign="top"
 
| Flash || 0x000000 ||0x0157FF || 86K<sup>[1]</sup>
 
|-valign="top"
 
| +--Flash: Reset Vector || 0x000000 ||0x000003 || 4
 
|-valign="top"
 
| +--Flash: Interrupt Vector Table || 0x000004 ||0x0000FF || 252
 
|-valign="top"
 
| +--Flash: Alternate Vector Table || 0x000104 ||0x0001FF || 252
 
|-valign="top"
 
| +--Flash: User Program || 0x000200 ||0x0157FF || 85.5K
 
|-valign="top"
 
| Programming Executive || 0x800000 || 0x800FFF || 4K<sup>[1]</sup>
 
|-valign="top"
 
| Config  Registers || 0xF80000 || 0xF80017 || 24
 
|-valign="top"
 
| Device ID (0xE5) || 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 phathom byte.<br>
 
 
 
===dsPicBootloader and dsPicProgrammer===
 
*RTSP for dsPIC33F is different from dsPIC30F.
 
**Row size changes from 32 instructions (96bytes) to 64 instructions (192 bytes)
 
**Erase operation changes from 1 row to 8 rows
 
**No EEPROM
 
*With regards to the above changes, dsPicBootloader and dsPicProgrammer has been modified. In particular, dsPicProgrammer can be used to program both dsPic30F and dsPic33F devices. You can easily add your devices to the source code.
 
 
 
 
 
==Downloads==
 
{| border="1" cellspacing="0" cellpadding="5"
 
|+ Table 12.1 Related software download links for dsPicBootloader and dsPicProgrammer
 
! Program
 
! Site 1
 
! Site 2
 
! Remarks
 
|- valign="top"
 
| JDK
 
| [http://java.sun.com/javase/downloads/index.jsp website]
 
|
 
| Download latest JDK
 
|- valign="top"
 
| RXTX
 
| [http://users.frii.com/jarvi/rxtx/download.html website]
 
|
 
| Download rxtx-2.1-7-bins-r2.zip or later
 
|- valign="top"
 
| dsPicBootloader
 
| [http://chungyan5.no-ip.org/websvn/listing.php click]
 
| [http://www.opencircuits.com/images/a/a7/DsPicBootloader_1_3_1.zip click]
 
| Under "dsPicBootloader/", download bl_5011.s or bl_j128gp306.s
 
|-valign="top"
 
| dsPicProgrammer
 
| [http://chungyan5.no-ip.org/websvn/listing.php click]
 
| [http://www.opencircuits.com/images/e/e1/DsPicProgrammer_1_3_2.zip click]
 
| Under "dsPicProgrammer/", dowload dsPicProgrammer.jar<br><br>Alternatively, if you want to compile yourself or modify the source code, download <br>all source files under "dsPicProgrammer/" '''plus''' RdFileIntelHex.java under <br>"IntelHexPaser/tags/0.02.00/".<br>You should also install RXTX on your local machine as recommended in the readme file.
 
|- valign="top"
 
| Ingenia's bootloader
 
| [http://www.ingenia-cat.com/en/downloads.php website]
 
|
 
| Download original ingenia's bootloader
 
|-
 
|}
 

Latest revision as of 06:30, 16 October 2012

This project aims to provide the development tools for building a multi-purpose MCU board. Description is based on Microchip dsPic33FJ256GP506 (was dsPic30F5011), but information provided in this wiki may give useful directions for developing similar embedded systems with different platforms.

Introduction

Features of dsPic33FJ256GP506

  • 3.0 to 3.3 V
  • Up to 40 MIPs
  • Maximum current sink/source for I/O pins: 4 mA
  • 16-bit arithmetics
  • DSP Instruction Set
  • Dual programming techniques: ICSP and RTSP
  • Memory
    • 256 KB flash (86K instructions)
    • 16 KB RAM (incl. 2 KB DMA RAM)
    • No EEPROM
  • Communications ports
    • UART
    • I2C: up to 1 Mbit/s
    • SPI
  • ADC
  • 10-bit A/D, 1.1 Msps
  • 12-bit A/D, 500 ksps
  • No DAC (PWMs only)
  • Pin-to-pin compatible with other dsPICs
Comparison between different dsPICs
dsPic *Price
US$
MIPs Flash
(kB)
RAM
(kB)
EEPROM
(kB)
I/O ADC
12-bit
IC OC Motor
Ctrl
Timers QEI UART SPI I2C CAN Codec
33FJ256GP506 6.11 40 256 16 0 53 18 8 8 0 9x16bit
4x32bit
0 2 2 2 1 1
33FJ128GP206 4.62 40 128 8 0 53 18 8 8 0 9x16bit
4x32bit
0 2 2 1 0 1
33FJ128GP306 4.81 40 128 16 0 53 18 8 8 0 9x16bit
4x32bit
0 2 2 2 0 1
33FJ128GP706 5.49 40 128 16 0 53 18 8 8 0 9x16bit
4x32bit
0 2 2 2 2 1
33FJ128MC506 4.97 40 128 8 0 53 16 8 8 8 9x16bit
4x32bit
1 2 2 2 1 0
33FJ128MC706 5.38 40 128 16 0 53 16 8 8 8 9x16bit
4x32bit
1 2 2 2 1 0

*For reference only, subject to change

Forums

  • Microchip: Official forum by Microchip
    • See MPLAB ICD 2, MPLAB IDE, MPLAB C30 Compiler, ASM30, Link30 forum, dsPIC30F Topics, dsPic33 topics
  • HI-TECH Software Forum: Discussion on dsPICC, a C compiler developed by HI-TECH
  • FreeRTOS Real Time Kernel: Open Discussion and Support on FreeRTOS
  • Nabble: MicroControllers - GNUPIC

References

Code Examples

Related Development


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.
  • 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 Used by ICSP
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


Available Programmers in the Market
Product Name Interface with PC Interface with Device *Price (US) Remarks
MPLAB® ICD 2 USB or RS232 6-PIN RJ-12 connector $159.99 -
Clone Microchip ICD2 (Now Using) USB 6-pin flat cables $52.35 Do not work with new MPLAB versions (works for 7.50), communication to MPLAB may sometime hang (see manual)

*For reference only (exclude shipping), subject to change


DIY ICD 2 Programmer Circuit
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.
Summary of IDE
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 Assembler and C-Compiler Linux Free
  1. Full-featured for the first 60 days. After 60 days, some code optimization functions are disabled. The compiler will continue to function after 60 days, but code size may increase.

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.


Development Environment

Windows

PIC setup win.JPG

  • 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.


C Libraries in MPLAB C30
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 \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

PIC setup linux.JPG

  • 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
  • Important Note: Only the compiler is free. The header files and library are owned by Microchip.
Pic30 C-Compiler Toolchain Templates for Conversion to Debian-based systems
Toolchain Source Instruction Remarks
v2.00 Download pic30-gcc-2.00-1.i386.rpm and pic30-binutils-2.00-1.i386.rpm.
Convert to deb files.
Stable
Now using
v2.05 Reference to example below, but use 2.05 files Can compile
Stable but not heavily tested
v3.01 Follow example below Can compile
Unstable (sometime produce segmentation fault)
v3.10 Reference to example below, but use 3.10 files Cannot compile yet (segmentation fault)

Conversion Example

  • Pre-install these packages: dpkg-dev, debhelper, bison, flex, sysutils, gcc-3.3, fakeroot
    • cmd: sudo apt-get install dpkg-dev debhelper bison flex sysutils gcc-3.3 fakeroot
  • Download and unzip template: pic30-3.01.tar.bz2
  • Download assembler: mplabalc30v3_01_A.tar.gz. Save under /pic30-3.01/pic30-binutils-3.01/upstream/
  • Download c-compiler: mplabc30v3_01_A.tgz. Save under /pic30-3.01/pic30-gcc-3.01/upstream/
  • Install MPLAB_C30_v3_01-StudentEdition under Windows
  • Copy directories /include, /lib, /support, and /bin/c30_device.info to pic30-3.01/pic30-support-3.01/upstream/
  • Pack pic30-binutils into deb file
    • goto /pic30-3.01/pic30-binutils-3.01/
    • type cmd: dpkg-buildpackage -rfakeroot -b
  • Install pic30-binutils_3.01-1_i386.deb
    • type cmd: sudo dpkg -i pic30-binutils_3.01-1_i386.deb
  • Pack pic30-gcc-3.01 into deb file
    • goto /pic30-3.01/pic30-gcc-3.01/
    • type cmd: dpkg-buildpackage -rfakeroot -b
  • Install pic30-gcc_3.01-1_i386.deb
    • type cmd: sudo dpkg -i pic30-gcc_3.01-1_i386.deb
  • Pack support files into deb file
    • goto /pic30-3.01/pic30-support-3.01/
    • type cmd: dpkg-buildpackage -rfakeroot -b
  • Install pic30-support_3.01-1_all.deb
    • type cmd: sudo dpkg -i pic30-support_3.01-1_all.deb
  • After installation, locations of
    • C-Header (*.h): /usr/pic30-elf/include
    • Libraries (*.a): /usr/pic30-elf/lib
    • Assembly header (*.inc): /usr/share/pic30-support/inc
    • Linkerscript (*.gld): /usr/share/pic30-support/gld

Burning Program Codes to Target Board

  1. Use 'dspicprg and dspicdmp' utilities developed by Homer Reid to burn hex code (*.hex) to devices. See Reference here. Through serial port only?
  2. Use Piklab IDE. Details on file format not known.
  3. Use MPLAB IDE to burn hex code (*.hex) to devices.

Code Optimization

  • Below is a comparsion between different optimization levels for the project including drivers for 2 projects.
Comparison between differnt optimization levels
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%)


Driver Development

  • Description on developing drivers with POSIX API


Bootloader Development

  • Description on concepts and development on bootloader
  • Description on dsPicProgrammer to download firmware via bootloader


Programming the Device

  • Description on how to use dsPicProgrammer to download firmware to dspic