PIC32 + RTC a través de SPI no funciona

1

Estoy intentando leer la hora desde un RTC con mi Microcontrolador PIC32 a través de SPI. Ya he logrado leer el tiempo con un Arduino del RTC.

PIC32 : enlace (Documentación, Hoja de datos)
RTC : enlace (Documentación, Hoja de datos)
Arduino : Arduino Pro Mini

Problema : de alguna manera, los valores que lee el PIC32 del RTC no son correctos. Tal vez los valores no se lean o almacenen correctamente con el PIC32. Por ejemplo, el valor de los segundos leídos del RTC solo está por debajo de 30 cuando el RTC realmente está entre los segundos 50 y 59. (El segundo valor% 2 sigue siendo = 0 cada dos segundos). No sé por qué obtengo esos valores extraños de la RTC.

Códigos : he incluido ambos ejemplos de código: la versión de trabajo de Arduino y la versión de PIC32 que no funciona.

Versión de trabajo de Arduino:

#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;   
    }
  }
}

Versión de PIC32 que no funciona:

#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;
        }
    }
}

Posibles errores:

  • No sé si es necesario configurar BITOrder en MSBFirst en el PIC32. (como en la versión Arduino) (y no sé cómo)
  • Es posible que BaudRate no esté configurado correctamente. (aunque lo obtuve de un gran tutorial)
  • Las conversiones de tipo y valor y las operaciones de bit en la función ReadTime () no se pueden manejar de la misma manera que en el Arduino, lo que podría causar la lectura de valores extraños en el RTC

Versión de PIC32 RTCC no funciona:

Aquí hay un fragmento de código que he hecho para usar para el módulo RTCC en el UBW32.

No funciona, ya que los minutos aparecen impares todo el tiempo en la prueba.

No sé si necesito más definiciones de pines, o si debo unir un cristal.

Aquí está el esquema. A mi me parece que se incluye un cristal: enlace

// 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;
        }
    }
}

¿Alguien tiene una idea de cómo puedo obtener los valores correctos con el PIC32?

    
pregunta ndrizza

1 respuesta

0

Entonces, gracias a la ayuda de todos, aquí hay una solución alternativa que utiliza el RTCC de la imagen.

Esta solución tiene mucho más sentido que leer el tiempo desde un módulo SPI externo.

puedes comprar un cristal 32.768 como este: enlace

y dos cristales de 11pf o 12 pf y alinéelos como se muestra en este esquema (arriba a la derecha): enlace

Lo que aún no he descubierto es cómo alimentar el RTC con una batería adicional. Si alguien sabe cómo me gustaría un post!

Aquí hay un código de ejemplo de trabajo:

// 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.sec%2;
        switch(minutes){
            case 0:
                PORTA = 0b0000000000000000;
                PORTB = 0b1111111111111111;
                break;
            case 1:
                PORTA = 0b1111111111111111;
                PORTB = 0b0000000000000000;
                PORTA._RA0 = 0;

                break;
        }
    }
}
    
respondido por el ndrizza

Lea otras preguntas en las etiquetas