[SOLVED] DS3231 module no I2C ACK

Thread Starter

AlbertHall

Joined Jun 4, 2014
12,623
I am trying to use a DS3231 module as a source of accurate 1Hz clock, however I get no signal on int/sqw and no ACK on the I2C (using address 0xD0 - 0x78). I get the 32kHz output OK. I have removed the battery socket from the module as I don't need teh RTC.

An OLED on the same I2C works correctly.

Do I need to do anything other than connect power and I2C?
Do I just have a duff DS3231?
 

Thread Starter

AlbertHall

Joined Jun 4, 2014
12,623
MPLABX v6.25, XC8 v3.10.
Here is all the code:
C:
//  OLED counter for GDO           

// Compile with MPLABX v3.10 and XC8 v1.45 
// This code is free to use, for more info   http://www.moty22.co.uk    

// Pin Usage:
// RC1  Input Signal
// RC2  PPS T1CKI and C1OUT
// RC3  SDA
// RC4  SCL
// RC5  1Hz Square wave input


// PIC16F15325 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // External Oscillator mode selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1)
#pragma config CLKOUTEN = OFF   // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
#pragma config CSWEN = OFF      // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (FSCM timer disabled)

// CONFIG2
#pragma config MCLRE = ON       // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config LPBOREN = OFF    // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = OFF      // Brown-out reset enable bits (Brown-out reset disabled)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF        // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = OFF    // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will not cause a reset)

// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG4
#pragma config BBSIZE = BB512   // Boot Block Size Selection bits (512 words boot block size)
#pragma config BBEN = OFF       // Boot Block Enable bit (Boot Block disabled)
#pragma config SAFEN = OFF      // SAF Enable bit (SAF disabled)
#pragma config WRTAPP = OFF     // Application Block Write Protection bit (Application Block not write protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block not write protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration Register not write protected)
#pragma config WRTSAF = OFF     // Storage Area Flash Write Protection bit (SAF not write protected)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming)

// CONFIG5
#pragma config CP = OFF         // UserNVM Program memory code protection bit (UserNVM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#include <stdint.h>
#include <stdbool.h>

#include "OLED_Font.h"

#define _XTAL_FREQ 32000000
#define SDA RA2
#define SCL RC0
#define SDAio TRISA2 //SDA input or output
#define yi 0
#define RTCaddr 0xD0        // DS3231 I2C address

//prototypes
void command(unsigned char comm);
void oled_init(void);
void clrScreen(void);
bool sendData(unsigned char dataB);
void startBit(void);
void stopBit(void);
void clock(void);
bool clockA(void);
void drawChar2(char fig, unsigned char y, unsigned char x);
void SetSQW(void);
void ComparatorSetup(void);
void SetupPPS(void);
void I2C_Scan(void);


unsigned char addr = 0x78; //0b1111000
uint16_t Freq;
unsigned long Ovf;
uint8_t OvfCount;
bool NewReading = false;

void main(void)
{
    unsigned long f, total; //
    unsigned char timebase, i, d[8]; //,nz
    unsigned int freq2;
    // PIC I/O init
    SetupPPS();
    ANSELA = 0;
    ANSELC = 0x02; // RC1 as analogue for comparator input
    TRISC = 0b00001000; // RC3 as SDA input and RC4 as SCLoutput
    ComparatorSetup();
    SDAio = 0;
    SCL = 1;
    SDA = 1;
    __delay_ms(1000);
    
    while(0)
    {
    I2C_Scan();
    }
    SetSQW(); // Setup 1Hz square wave
    oled_init(); //number of rows in OLED
    clrScreen(); // clear screen

    drawChar2(11, 2, 8); //H
    drawChar2(12, 2, 9); //z
    __delay_ms(1000);

    TMR1 = 0;
    OvfCount = 0;
    INTF = 0;
    INTE = 1;
    TMR1IF = 0;
    TMR1IE = 1;
    PEIE = 1;
    GIE = 1;
    while (1)
    {
    NewReading = true;
        if (NewReading)
        {
            NewReading = false;
            total = Freq + (Ovf << 16);
            total = 150000;
            f = total;
            for (i = 0; i < 8; ++i)
            {
                d[i] = f % 10;
                f = f / 10;
            }
            if (total > 9999999)
            {
                drawChar2(d[7], yi, 0);
            } else
            {
                drawChar2(10, yi, 0);
            }
            if (total > 999999)
            {
                drawChar2(d[6], yi, 1);
                drawChar2(13, yi, 2);
            } else
            {
                drawChar2(10, yi, 1);
                drawChar2(10, yi, 2);
            }
            if (total > 99999)
            {
                drawChar2(d[5], yi, 3);
            } else
            {
                drawChar2(10, yi, 3);
            }
            if (total > 9999)
            {
                drawChar2(d[4], yi, 4);
            } else
            {
                drawChar2(10, yi, 4);
            }
            if (total > 999)
            {
                drawChar2(d[3], yi, 5);
                drawChar2(13, yi, 6);
            } else
            {
                drawChar2(10, yi, 5);
                drawChar2(10, yi, 6);
            }
            drawChar2(d[2], yi, 7);
            drawChar2(d[1], yi, 8);
            drawChar2(d[0], yi, 9);
        }
    }
}

void __interrupt() isr(void)
{
    if (INTF)
    {
        INTF = 0;
        // One second elapsed - store cycle count
        Freq = TMR1;
        TMR1 = 0;
        Ovf = OvfCount;
        OvfCount = 0;
        NewReading = true;
    }

    if (TMR1IF)
    {
        TMR1IF = 0;
        OvfCount++;
    }
}

//size 2 chars
void drawChar2(char fig, unsigned char y, unsigned char x)
{
    unsigned char i, line, btm, top; //

    command(0x20); // vert mode
    command(0x01);

    command(0x21); //col addr
    command(13 * x); //col start
    command(13 * x + 9); //col end
    command(0x22); //0x22
    command(y); // Page start
    command(y + 1); // Page end

    startBit();
    sendData(addr); // address
    sendData(0x40);

    for (i = 0; i < 5; i++)
    {
        line = font[5 * (fig) + i];
        btm = 0;
        top = 0;
        // expend char    
        if (line & 64)
        {
            btm += 192;
        }
        if (line & 32)
        {
            btm += 48;
        }
        if (line & 16)
        {
            btm += 12;
        }
        if (line & 8)
        {
            btm += 3;
        }

        if (line & 4)
        {
            top += 192;
        }
        if (line & 2)
        {
            top += 48;
        }
        if (line & 1)
        {
            top += 12;
        }

        sendData(top); //top page
        sendData(btm); //second page
        sendData(top);
        sendData(btm);
    }
    stopBit();

    command(0x20); // horizontal mode
    command(0x00);
}

void clrScreen() //fill screen with 0
{
    unsigned char y, i;

    for (y = 0; y < 8; y++)
    {
        command(0x21); //col addr
        command(0); //col start
        command(127); //col end
        command(0x22); //0x22
        command(y); // Page start
        command(y + 1); // Page end    
        startBit();
        sendData(addr); // address
        sendData(0x40);
        for (i = 0; i < 128; i++)
        {
            sendData(0x00);
        }
        stopBit();
    }
}

//Software I2C
bool sendData(unsigned char dataB)
{
    bool Local;
    
    for (unsigned char b = 0; b < 8; b++)
    {
        Local = (dataB >> (7 - b)) & 0x01;
        SDA = Local;
        clock();
    }
    SDAio = 1; //SDA input
    Local = clockA();
    __delay_us(5);
    SDAio = 0; //SDA output
    return (Local);
}

void clock(void)
{
    __delay_us(5);
    SCL = 1;
    __delay_us(10);
    SCL = 0;
    __delay_us(5);
}


bool clockA(void)
{
    uint8_t ACK;
    __delay_us(5);
    SCL = 1;
    __delay_us(10);
    ACK = SDA;
    SCL = 0;
    __delay_us(5);
    return ACK;
}


void startBit(void)
{
    SDA = 0;
    __delay_us(10);
    SCL = 0;

}

void stopBit(void)
{
    SCL = 1;
    __delay_us(10);
    SDA = 1;
}

void command(unsigned char comm)
{

    startBit();
    sendData(addr); // address
    sendData(0x00);
    sendData(comm); // command code
    stopBit();
}

void oled_init()
{
    command(0xAE); // DISPLAYOFF
    command(0x8D); // CHARGEPUMP *
    command(0x14); //0x14-pump on
    command(0x20); // MEMORYMODE
    command(0x0); //0x0=horizontal, 0x01=vertical, 0x02=page
    command(0xA1); //SEGREMAP * A0/A1=top/bottom 
    command(0xC8); //COMSCANDEC * C0/C8=left/right
    command(0xDA); // SETCOMPINS *
    command(0x22); //0x22=128x32(4rows), 0x12=128x64(8rows)
    command(0x81); // SETCONTRAST
    command(0x8F); //0x8F
    //next settings are set by default
    //    command(0xD5);  //SETDISPLAYCLOCKDIV 
    //    command(0x80);  
    //    command(0xA8);       // SETMULTIPLEX
    //    command(0x3F);     //0x1F
    //    command(0xD3);   // SETDISPLAYOFFSET
    //    command(0x0);  
    //    command(0x40); // SETSTARTLINE  
    //    command(0xD9);       // SETPRECHARGE
    //    command(0xF1);
    //    command(0xDB);      // SETVCOMDETECT
    //    command(0x40);
    //    command(0xA4);     // DISPLAYALLON_RESUME
    //   command(0xA6);      // NORMALDISPLAY
    command(0xAF); //DISPLAY ON
}

void SetSQW(void)
{
    startBit();
    sendData(RTCaddr); // address
    sendData(0x0E);
    sendData(0x00);
    stopBit();
}

void ComparatorSetup(void)
{
    C1HYS = 1; // Hysteresis on
    CM1PCHbits.PCH = 5; // Positive input is DAC output
    CM1NCHbits.NCH = 1; // Negative input is C1IN1-

    // FVR setup
    FVRCON = 0b11001111; // FVR is 4.096V

    // DAC setup
    DAC1CON0 = 0b10001000; // DAC input is FVR
    DAC1CON1 = 12; // 0-31 is 0 to 4.096V
}

void SetupPPS(void)
{
    // RC1 is T1CKI
    // RC1 is C1OUT
    GIE = 0;
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
    RC1PPS = 0b10110; // RC1 is C1 output
    T1CKIPPS = 0b10001; // RC1 is T1CKI
    INTPPS = 0b10101; // RC5 is INT
    PPSLOCKbits.PPSLOCKED = 1;
}

void I2C_Scan(void)
{
    uint8_t Addr;
    uint8_t Ack;
    
    for(uint8_t i = 8; i < 127; i++)
    {
        startBit();
        if(sendData(i))
        {}
        else
            NOP();
        stopBit();
    }
}
 

hexreader

Joined Apr 16, 2011
619
That is what I used to do for DS1307. To cure intermittency.

Not tried DS3231 without a battery, so cannot be sure it works the same. I recommend a careful reading of the datasheet in case I am reading it wrong
 

hexreader

Joined Apr 16, 2011
619
Just noticed this in the datasheet too:

"
Active-Low Interrupt or Square-Wave Output. This open-drain pin requires an external pullup resistor connected
to a supply at 5.5V or less.
"
 

Jon Chandler

Joined Jun 12, 2008
1,572
As I recall, a register bit must be set to enable/start the DS3231, which is designed to preserve battery life in products while stored and being shipped before first use.
 

joeyd999

Joined Jun 6, 2011
6,249
Newreading is always true, except for potentially the few nanoseconds between setting it true and testing it (assuming an interrupt occurs between those two instructions).

Is this what your intended?
 

Thread Starter

AlbertHall

Joined Jun 4, 2014
12,623
Newreading is always true, except for potentially the few nanoseconds between setting it true and testing it (assuming an interrupt occurs between those two instructions).

Is this what your intended?
No, that was for testng the display because util I have got the 1Hz square wave working it can't actually take any frequency readings.
 
Top