I'm trying to read the time from an RTC with my PIC32 Microcontroller via SPI. I've already succeeded in reading the time with an Arduino from the RTC.
PIC32: http://www.sparkfun.com/products/9713 (Documentation, Datasheet)
RTC: http://www.sparkfun.com/products/10160 (Documentation, Datasheet)
Arduino: Arduino Pro Mini
Problem: Somehow the values which the PIC32 reads from the RTC aren't correct. Maybe the values aren't read or stored correctly with the PIC32. For example the value of the seconds read from the RTC is only below 30 when the RTC actually is between the seconds 50 to 59. (The second value % 2 is still = 0 every two seconds.) I don't know why I get those weird values from the RTC.
Codes: I've included both code examples: the working Arduino version, and the not working PIC32 version.
Working Arduino Version:
#include <SPI.h>
const int cs=10; //chip select
int TimeDate[7]; //second,minute,hour,null,day,month,year
void setup() {
Serial.begin(9600);
pinMode(cs,OUTPUT); // chip select
pinMode(8,OUTPUT); // LED light
// start the SPI library:
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work
//set control register
digitalWrite(cs, LOW);
SPI.transfer(0x8E);
SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
digitalWrite(cs, HIGH);
delay(10);
}
void loop() {
ReadTimeDate();
// (TimeDate[0] contains the seconds read from the rtc)
if(TimeDate[0]<30) digitalWrite(8, HIGH); // works perfectly, is on from 0 t0 30
else digitalWrite(8, LOW);
delay(50);
}
void ReadTimeDate(){
for(int i=0; i<=6;i++){
if(i==3) i++;
digitalWrite(cs, LOW);
SPI.transfer(i+0x00);
unsigned int n = SPI.transfer(0x00);
digitalWrite(cs, HIGH);
int a=n & B00001111;
if(i==2){
int b=(n & B00110000)>>4; //24 hour mode
if(b==B00000010) b=20;
else if(b==B00000001) b=10;
TimeDate[i]=a+b;
}else if(i==4){
int b=(n & B00110000)>>4;
TimeDate[i]=a+b*10;
}else if(i==5){
int b=(n & B00010000)>>4;
TimeDate[i]=a+b*10;
}else if(i==6){
int b=(n & B11110000)>>4;
TimeDate[i]=a+b*10;
}else{
int b=(n & B01110000)>>4;
TimeDate[i]=a+b*10;
}
}
}
Not working PIC32 Version:
#include <p32xxxx.h>
#include <plib.h>
// configure bit settings
#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
#pragma config POSCMOD = XT, FNOSC = PRIPLL, FPBDIV = DIV_1, CP = OFF, BWP = OFF
// I/O Definitions
#define CS _RG9 // chip select
#define TCS _TRISG9 // tris control for CS pin
#define SYS_FREQ (80000000L)
int TimeDate[7]; //second,minute,hour,null,day,month,year
// send one byte of data and receive one back at the same time
char writeSPI2( char i ) {
SPI2BUF = i; // write to buffer for TX
while( !SPI2STATbits.SPIRBF ); // wait for TX complete
return SPI2BUF; // read the received values
}
// delay in microseconds function
void delay_us( delay ) {
// note that 1 core tick = 2 SYS cycles (this is fixed)
int us_ticks=( SYS_FREQ / 1000000 ) / 2;
WriteCoreTimer( 0 );
while( ReadCoreTimer() < delay*us_ticks );
}
main() {
SYSTEMConfig( SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE );
mOSCSetPBDIV( OSC_PB_DIV_2 ); // added
// Open core timer for delay function
OpenCoreTimer( 0xFFFFFFFF );
// SPI config
// CKP (clock polarity control) = 0
// CKE (clock edge control) = 1
// 8-bit, Master Mode
// Baud = 4MHz (Fpb/20 = 80/20 MHz)
SpiChnOpen( 2, SPICON_MSTEN | SPICON_CKE | SPICON_ON, 20 );
// initialize the SPI peripheral
TCS = 0; // make CS pin output
CS = 1; // release chip
// 2. RTC settings
delay_us( 1000000 ); // wait 1s
CS = 0;
delay_us( 40000 ); // delay 40ms
writeSPI2(0x8E);
writeSPI2(0x60); // 60 = disable Osciallator and Battery SQ wave @1hz,
// temp compensation, Alarms disabled
CS = 1;
delay_us( 10000 );
// 3. Pin settings (to visualize feedback)
DDPCONbits.JTAGEN = 0; // disable JTAGport, free up PORTA
TRISA = 0b0000000000000000; // all PORTA as output (0 = 0 utput , 1 = 1 nput)
// main loop
while(1) {
ReadTimeDate();
if( TimeDate[0] < 30 ) PORTA = 0b1111111111111111; // does not work at all, the LED is on from 50 to 59 (why??????)
else PORTA = 0b0000000000000000;
delay_us( 5000 );
}
}
ReadTimeDate() {
int i; // change TODO: changed to char
for (i = 0; i <= 6; i++) {
if (i == 3)
i++;
CS = 0;
writeSPI2(i + 0x00);
unsigned int n = writeSPI2(0x00);
CS = 1;
int a = n & 0b00001111;
if (i == 2) {
int b = (n & 0b00110000) >> 4; //24 hour mode
if (b == 0b00000010) b = 20;
else if (b == 0b00000001) b = 10;
TimeDate[i] = a + b;
} else if (i == 4) {
int b = (n & 0b00110000) >> 4;
TimeDate[i] = a + b * 10;
} else if (i == 5) {
int b = (n & 0b00010000) >> 4;
TimeDate[i] = a + b * 10;
} else if (i == 6) {
int b = (n & 0b11110000) >> 4;
TimeDate[i] = a + b * 10;
} else {
int b = (n & 0b01110000) >> 4;
TimeDate[i] = a + b * 10;
}
}
}
Possible errors:
- I don't know if it's necessary to set the setting of the BITOrder to MSBFirst on the PIC32. (like in the Arduino version) (and I don't know how)
- The BaudRate might not be set correct. (altough I got it from a great tutorial)
- The type and value conversions and the bit operations in the ReadTime() function can't be handled in the same way as on the Arduino, which might cause the strange values read from the RTC
Not Working PIC32 RTCC Version:
Here's a code snippet i've done to use for the RTCC module on the UBW32.
It is not working, as the minutes show up to be odd all the time in the test.
I don't know if I need further pin definitions, or if I should attach a crystal.
Here's the schematic. It looks to me like a crystal is included: http://schmalzhaus.com/UBW32/EE/v26/UBW32_MX795_v26_sch.pdf
// Master header file for all peripheral library includes
#include <plib.h>
// configuration settings
#pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
int main(void) {
rtccTime tm; // time structure
rtccDate dt; // date structure
// Configure the device for maximum performance.
// This macro sets flash wait states, PBCLK divider and DRM wait states based on the specified
// clock frequency. It also turns on the cache mode if avaialble.
// Based on the current frequency, the PBCLK divider will be set at 1:2. This knoweldge
// is required to correctly set UART baud rate, timer reload value and other time sensitive
// setting.
SYSTEMConfigPerformance(72000000L);
RtccInit(); // init the RTCC
while(RtccGetClkStat()!=RTCC_CLK_ON); // wait for the SOSC to be actually running and RTCC to have its clock source
// could wait here at most 32ms
RtccOpen(0x10073000, 0x07011602, 0); // set time and date (- actually i don't know what time is set, but for the moment it doesn't matter.)
// time is MSb: hour, min, sec, rsvd. date is MSb: year, mon, mday, wday.
// please note that the rsvd field has to be 0 in the time field!
RtccGetTimeDate(&tm, &dt); // get current time
DDPCONbits.JTAGEN = 0; // disable JTAGport, free up PORTA
TRISA = 0b0000000000000000;
TRISB = 0b0000000000000000;
while(1){
RtccGetTimeDate(&tm, &dt);
// test: minutes odd or even
int minutes = tm.min%2;
switch(minutes){
case 0:
PORTA = 0b0000000000000000;
PORTB = 0b1111111111111111;
break;
case 1:
PORTA = 0b1111111111111111;
PORTB = 0b0000000000000000;
break;
}
}
}
Does someone have an idea how i could get the correct values with the PIC32?