Chapter 8 Communication Introduction to serial communication interfaces. Examples of use of the SPI module Synchronous Serial Interfaces Di Jasio - Programming 32-bit Microcontrollers in C SPI bus Di Jasio - Programming 32-bit Microcontrollers in C Asynchronous Serial Interfaces Di Jasio - Programming 32-bit Microcontrollers in C Serial Interfaces Side by Side Di Jasio - Programming 32-bit Microcontrollers in C SPI module figure 17-1 (DS61143) Di Jasio - Programming 32-bit Microcontrollers in C SPIxCON Di Jasio - Programming 32-bit Microcontrollers in C SPI module basic setup // configuration bit settings, Fcy=72MHz, Fpb=9MHz #pragma config POSCMOD=XT, FNOSC=PRIPLL #pragma config FPLLIDIV=DIV_2, FPLLMUL=MUL_18, FPLLODIV=DIV_1 #pragma config FPBDIV=DIV_8, FWDTEN=OFF, CP=OFF, BWP=OFF #define SPI_BAUD 15 // Fpb/(2 * (15+1)) = 1:32 Provides a clock of 9MHz / 32 = ~ 280kHz // peripheral configurations #define SPI_CONF 0x8120 // SPI on, 8-bit master,CKE=1,CKP=0 Di Jasio - Programming 32-bit Microcontrollers in C Reading and Writing // I/O definitions #define CSEE #define TCSEE _RD12 _TRISD12 // 1. init the SPI peripheral TCSEE = 0; // CSEE = 1; // SPI2CON = SPI_CONF; // SPI2SPI2BRG = SPI_BAUD; // // select line for EEPROM // tris control for CSEE pin make SSEE pin output de-select the EEPROM select mode and enable select clock speed // send one byte of data and receive int writeSPI2( int i) { SPI2BUF = i; // while( !SPI2STATbits.SPIRBF); // return SPI2BUF; // }//writeSPI2 Di Jasio - Programming 32-bit Microcontrollers in C one back at the same time write to buffer for TX wait for transfer complete read the received value Serial EEPROM Commands // 25LC256 Serial EEPROM commands #define SEE_WRSR 1 // write status register #define SEE_WRITE 2 // write command #define SEE_READ 3 // read command #define SEE_WDI 4 // write disable #define SEE_STAT 5 // read status register #define SEE_WEN 6 // write enable Di Jasio - Programming 32-bit Microcontrollers in C Serial EEPROM Status Register 25LC256 Status register detail (DS21822) Di Jasio - Programming 32-bit Microcontrollers in C Writing Data to the EEPROM // send a Write command CSEE = 0; // select the Serial EEPROM writeSPI2( SEE_WRITE); // send command, ignore data writeSPI2( ADDR_MSB); // send MSB of memory address writeSPI2( ADDR_LSB); // send LSB of memory address writeSPI2( data); // send the actual data // send more data here to perform a page write CSEE = 1; // start actual EEPROM write cycle Di Jasio - Programming 32-bit Microcontrollers in C Reading EEPROM Data // send a Read command CSEE = 0; writeSPI2( SEE_READ); writeSPI2( ADDR_MSB); writeSPI2( ADDR_LSB); // // // // data = writeSPI2( 0); // send dummy, read data select the Serial EEPROM send command, ignore data send MSB of memory address send LSB of memory address // read more data here sequentially incrementing the address ... // terminate the read sequence CSEE = 1; // and return to low power Di Jasio - Programming 32-bit Microcontrollers in C 32-bit Serial EEPROM Lib /* ** SEE Access Library */ #include "p32xxxx.h" #include "see.h" // I/O definitions #define CSEE _RD12 #define TCSEE _TRISD12 // select line for Serial EEPROM // tris control for CSEE pin // peripheral configurations #define SPI_CONF 0x8120 // SPI on, 8-bit master,CKE=1,CKP=0 #define SPI_BAUD 15 // clock divider Fpb/(2 * (15+1)) // 25LC256 Serial EEPROM commands #define SEE_WRSR 1 // write status register #define SEE_WRITE 2 // write command #define SEE_READ 3 // read command #define SEE_WDI 4 // write disable #define SEE_STAT 5 // read status register #define SEE_WEN 6 // write enable // send one byte of data and receive int writeSPI2( int i) { SPI2BUF = i; // while( !SPI2STATbits.SPIRBF); // return SPI2BUF; // }//writeSPI2 Di Jasio - Programming 32-bit Microcontrollers in C void initSEE( void) { // init the SPI2 peripheral CSEE = 1; TCSEE = 0; SPI2CON = SPI_CONF; SPI2BRG = SPI_BAUD; }// initSEE // // // // one back at the same time write to buffer for TX wait for transfer complete read the received value de-select the Serial EEPROM make SSEE pin output enable the peripheral select clock speed 32-bit Serial EEPROM Lib (cont.) int readStatus( void) { // Check the Serial EEPROM status register int i; CSEE = 0; // select the Serial EEPROM writeSPI2( SEE_STAT); // send a READ STATUS COMMAND i = writeSPI2( 0); // send/receive CSEE = 1; // deselect terminate command return i; } // readStatus int readSEE( int address) { // read a 32-bit value starting at an even address int i; // wait until any work in progress is completed while ( readStatus() & 0x1);// check WIP // perform a 32-bit read sequence, four byte sequential read CSEE = 0; // select the Serial EEPROM writeSPI2( SEE_READ); // read command writeSPI2( address >>8); // address MSB first writeSPI2( address & 0xfc); // address LSB (word aligned) i = writeSPI2( 0); // send dummy, read msb i = (i<<8)+ writeSPI2( 0); // send dummy, read lsb i = (i<<8)+ writeSPI2( 0); // send dummy, read lsb i = (i<<8)+ writeSPI2( 0); // send dummy, read lsb CSEE = 1; return ( i); }// readSEE Di Jasio - Programming 32-bit Microcontrollers in C 32-bit Serial EEPROM Lib (cont.) void writeEnable( void) { // send a Write Enable CSEE = 0; writeSPI2( SEE_WEN); CSEE = 1; }// writeEnable command // select the Serial EEPROM // write enable command // deselect to complete the command void writeSEE( int address, int data) { // write a 32-bit value starting at an even address // wait until any work in progress is completed while ( readStatus() & 0x1) // check the WIP flag // Set the Write Enable Latch writeEnable(); // perform CSEE = 0; writeSPI2( writeSPI2( writeSPI2( writeSPI2( writeSPI2( writeSPI2( writeSPI2( CSEE = 1; }// writeSEE a 32-bit write sequence (4 byte page write) // select the Serial EEPROM SEE_WRITE); // write command address>>8); // address MSB first address & 0xfc); // address LSB (word aligned) data >>24); // send msb data >>16); // send msb data >>8); // send msb data); // send lsb Di Jasio - Programming 32-bit Microcontrollers in C Tips and Tricks If you store important data in an external non volatile memory (SEE), you might want to put some additional safety measures in place (both hardware and software). From a hardware perspective make sure that: • Adequate power supply decoupling (capacitor) is provided close to the device. • A pull up resistor (10k Ohm) is provided on the Chip Select line, to avoid floating during the microcontroller power up and reset. • An additional pull down resistor (10k Ohm) can be provided on the SCK clock line to avoid clocking of the peripheral during power up when the PIC32 I/Os might be floating (tri-state). • Verify clean and fast power-up and down slopes are provided to the microcontroller to guarantee reliable Power-On Reset (POR) operation. If necessary add an external voltage supervisor (see MCP809 devices for example). Di Jasio - Programming 32-bit Microcontrollers in C Tips and Tricks A number of software methods can then be employed to prevent even the most remote possibility that a program bug or the proverbial cosmic ray might trigger the write routine. Here are some suggestions: •Avoid reading and especially updating the SEE content right after power up. Allow a few milliseconds for the power supply to stabilize (this is going to be heavily application dependent). •Add a software write-enable flag, and demand that the calling application set the flag before calling the write routine, possibly after verifying some application specific entry condition. •Add a stack level counter; each function in the stack of calls implemented by the library should increment the counter upon entry and decrement it on exit. The write routine should refuse to perform if the counter is not at the expected level. •Some users refuse to use the SEE memory locations corresponding to the first address (0x0000) and/or the last address (0xffff) believing they could be statistically more likely to be subject to corruption. •More seriously, store two copies of each essential piece of data, performing two separate calls to the write routine. If each copy contains a checksum or simply by comparison, when reading it back, it will be easy to identify a memory corruption problem and possibly recover. Di Jasio - Programming 32-bit Microcontrollers in C