STM32F411 Nucleo I2C DS3231 1Hz Square Wave with External Interrupt

1Hz SQW

Bare metal like.
A very basic demonstration of STM32 I2C communications with a DS3231 chip (in the form of a ChronoDot). The program uses I2C to communicate with the DS3231 chip. It sets the DS3231 date and time, and commands a 1Hz square output on the DS3231 SQW pin. The Nucleo PB1 pin is configured for an external rising-edge interrupt. The resulting interrupt causes the Nucleo LED to blink at 1Hz.

Additionally, if one presses the Nucleo blue button, the program fetches the current date and time from the DS3231 and then passes this information through the virtual comm port (USART#2). I received much help from and reused some of the code posted here.

Nucleo and DS3231

#include "stdint.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_it.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_i2c.h"
#include "serial.h"
#include "string.h"
#include "stdio.h"

//ChronoDot
//SQW  -----> Pb1 (tied thru 10kR to VCC) 
//GND  -----> GND 
//VCC  -----> 5V
//I2C1 GPIO Configuration    
//PB6 ------> I2C1_SCL
//PB7 ------> I2C1_SDA 
//Virtual Comm Port
//PA2
//PA3

#define DS3231_ADDRESS      0xd0 //I2C 7-bit slave address shifted for 1 bit to the left
#define DS3231_CONTROL_REG  0x0e
/* Registers location */
#define DS3231_SECONDS      0x00
#define DS3231_MINUTES      0x01
#define DS3231_HOURS        0x02
#define DS3231_DAY          0x03
#define DS3231_DATE         0x04
#define DS3231_MONTH        0x05
#define DS3231_YEAR         0x06

//Structure for date/time 
typedef struct {
  uint8_t seconds; //Seconds parameter, from 00 to 59 
  uint8_t minutes; //Minutes parameter, from 00 to 59 
  uint8_t hours;   //Hours parameter, 24Hour mode, 00 to 23 
  uint8_t day;     //Day in a week, from 1 to 7 
  uint8_t date;    //Date in a month, 1 to 31 
  uint8_t month;   //Month in a year, 1 to 12 
  uint8_t year;    //Year parameter, 00 to 99, 00 is 2000 and 99 is 2099 
} DS3231_Time_t;

//configure SystemCoreClock using HSI (HSE is not populated on Nucleo board)
void SystemCoreClockConfigure(void) {
  //enable HSI
  RCC->CR |= ((uint32_t)RCC_CR_HSION);                     
  while ((RCC->CR & RCC_CR_HSIRDY) == 0)
    ; //Wait for HSI Ready RCC->CFGR = RCC_CFGR_SW_HSI;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
    ; //wait for HSI used as system clock
  FLASH->ACR  = FLASH_ACR_PRFTEN;      //enable Prefetch Buffer
  FLASH->ACR |= FLASH_ACR_ICEN;        //instruction cache enable
  FLASH->ACR |= FLASH_ACR_DCEN;        //data cache enable
  FLASH->ACR |= FLASH_ACR_LATENCY_5WS; //flash 5 wait state
  //HCLK = SYSCLK
  RCC->CFGR |= RCC_CFGR_HPRE_DIV1;                         
  //APB1 = HCLK/2
  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;                        
  //APB2 = HCLK/1
  RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;                        
  //disable PLL
  RCC->CR &= ~RCC_CR_PLLON;                                
  //PLL configuration: VCO=HSI/M*N, Sysclk=VCO/P
  //PLL_M=16, PLL_N=320, PLL_P=4, PLL_SRC=HSI, PLL_Q=8 for 80MHz SYSCLK/APB2 40MHz APB1
  RCC->PLLCFGR = (16ul | (320ul<<6) | (1ul<<16) | (RCC_PLLCFGR_PLLSRC_HSI) | (8ul<<24));
  //enable PLL
  RCC->CR |= RCC_CR_PLLON;                                 
  //Wait till PLL is ready
  while((RCC->CR & RCC_CR_PLLRDY) == 0) 
    __NOP();
  //select PLL as system clock source
  RCC->CFGR &= ~RCC_CFGR_SW;                               
  RCC->CFGR |=  RCC_CFGR_SW_PLL;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
    ; //wait till PLL is system clock src
}

void ConfigureNucleoGPIOs(void) {
  //configure nucleo led (pa5) pin as output, push-pull, no pull-up/down 
  RCC->AHB1ENR |= (1ul<<0);                      //enable GPIOA peripheral clock
  GPIOA->MODER &= ~((3ul<<2*5));                //clear both mode bits
  GPIOA->MODER |= ((GPIO_Mode_OUT<<2*5));       //set as general purpose output
  GPIOA->OTYPER &= ~((1ul<<5));                 //clear (push/pull)
  GPIOA->OSPEEDR &= ~((3ul<<2*5));              //clear both speed bits
  GPIOA->OSPEEDR |= ((GPIO_Medium_Speed<<2*5)); //set medium speed
  GPIOA->PUPDR &= ~((3ul<<2*5));                //clear both pull up/down status (none)
  //configure nucleo blue button (pa13) pin as input, push-pull with pull-down 
  RCC->AHB1ENR |= (2ul<<1);                     //enable GPIOC clock
  GPIOC->MODER &= ~((3ul<<2*13));               //clear both mode bits
  GPIOC->MODER |= ((GPIO_Mode_IN<<2*13));       //set as input
  GPIOC->OTYPER &= ~((1ul<<13));                //clear (push/pull)
  GPIOC->OSPEEDR &= ~((3ul<<2*13));             //clear both speed bits
  GPIOC->OSPEEDR |= ((GPIO_High_Speed<<2*13));  //set high speed
  GPIOC->PUPDR |= (GPIO_PuPd_DOWN<<2*13);       //set pull down status
}

void SER_OutString(char *s) {
  while (*s)
    SER_PutChar(*s++);
}  

//
//i2c functions
//

#define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED        ((uint32_t)0x00070082)  /* BUSY, MSL, ADDR, TXE and TRA flags */
#define I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED           ((uint32_t)0x00030002)  /* BUSY, MSL and ADDR flags */
#define I2C_EVENT_MASTER_BYTE_RECEIVED                    ((uint32_t)0x00030040)  /* BUSY, MSL and RXNE flags */
#define I2C_TRANSMITTER_MODE   0
#define I2C_RECEIVER_MODE      1
#define I2C_ACK_ENABLE         1
#define I2C_ACK_DISABLE        0
#define FLAG_MASK ((uint32_t)0x00FFFFFF) //I2C FLAG mask

uint32_t I2CTimeout;

ErrorStatus I2CCheckEvent(uint32_t I2C_EVENT) {
  uint32_t lastevent = 0;
  uint32_t flag1 = 0;
  uint32_t flag2 = 0;
  ErrorStatus status = ERROR;

  //read the I2Cx status register
  flag1 = I2C1->SR1;
  flag2 = I2C1->SR2;
  flag2 = flag2<<16;
  //Get the last event value from I2C status register 
  lastevent = (flag1 | flag2)&FLAG_MASK;
  //Check whether the last event contains the I2C_EVENT 
  if ((lastevent & I2C_EVENT) == I2C_EVENT)
    //SUCCESS: last event is equal to I2C_EVENT 
    status = SUCCESS;
  else
    //ERROR: last event is different from I2C_EVENT 
    status = ERROR;
  //Return status 
  return status;
}

int16_t I2CStart(uint8_t address, uint8_t direction, uint8_t ack) {
  //generate I2C start pulse 
  I2C1->CR1 |= I2C_CR1_START;
  //wait till I2C is busy 
  I2CTimeout = 20000;
  while (!(I2C1->SR1&I2C_SR1_SB)) {
    if (--I2CTimeout == 0x00) 
      return 1;
  }
  //enable ack if we select it 
  if (ack) 
    I2C1->CR1 |= I2C_CR1_ACK;
  //send write/read bit 
  if (direction == I2C_TRANSMITTER_MODE) {
    //send address with zero last bit 
    I2C1->DR = address & ~I2C_OAR1_ADD0;
    //wait till finished 
    I2CTimeout = 20000;
    while (!(I2C1->SR1&I2C_SR1_ADDR)) {
      if (--I2CTimeout == 0x00) 
        return 1;
    }
  }
  if (direction == I2C_RECEIVER_MODE) {
    //send address with 1 last bit 
    I2C1->DR = address | I2C_OAR1_ADD0;
    //wait till finished 
    I2CTimeout = 20000;
    while (!I2CCheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
      if (--I2CTimeout == 0x00) 
        return 1;
    }
  }
  //read status register to clear ADDR flag 
  I2C1->SR2;
  //return 0, everything ok 
  return 0;
}

uint8_t I2CStop(void) {
  //wait till transmitter not empty 
  I2CTimeout = 20000;
  while (((!(I2C1->SR1&I2C_SR1_TXE)) || (!(I2C1->SR1&I2C_SR1_BTF)))) {
    if (--I2CTimeout == 0x00) 
      return 1;
  }
  //generate stop 
  I2C1->CR1 |= I2C_CR1_STOP;
  //return 0, everything ok 
  return 0;
}

uint8_t I2CReadAck(void) {
  uint8_t data;
  
  //enable ACK 
  I2C1->CR1 |= I2C_CR1_ACK;
  //wait till not received 
  I2CTimeout = 20000;
  while (!I2CCheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) {
    if (--I2CTimeout == 0x00) 
      return 1;
  }
  //read data 
  data = I2C1->DR;
  //return data 
  return data;
}

uint8_t I2CReadNack(void) {
  uint8_t data;
  
  //disable ACK 
  I2C1->CR1 &= ~I2C_CR1_ACK;
  //generate stop 
  I2C1->CR1 |= I2C_CR1_STOP;
  //wait till received 
  I2CTimeout = 20000;
  while (!I2CCheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) {
    if (--I2CTimeout == 0x00) 
      return 1;
  }
  //read data 
  data = I2C1->DR;
  //return data
  return data;
}

void I2CWriteData(uint8_t data) {
  //wait till I2C is not busy anymore 
  I2CTimeout = 20000;
  while (!(I2C1->SR1 & I2C_SR1_TXE) && I2CTimeout) 
    I2CTimeout--;
  //send I2C data 
  I2C1->DR = data;
}

void I2CWrite(uint8_t address, uint8_t reg, uint8_t data) {
  I2CStart(address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
  I2CWriteData(reg);
  I2CWriteData(data);
  I2CStop();
}

uint8_t I2CRead(uint8_t address, uint8_t reg) {
  uint8_t data;

  I2CStart(address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
  I2CWriteData(reg);
  I2CStop();
  I2CStart(address, I2C_RECEIVER_MODE, I2C_ACK_DISABLE);
  data = I2CReadNack();
  return data;
}

void I2CWriteMulti(uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
  uint8_t i;
  
  I2CStart(address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE);
  I2CWriteData(reg);
  for (i = 0; i < count; i++) 
    I2CWriteData(data[i]);
  I2CStop();
}

void I2CReadMulti(uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) {
  uint8_t i;
  
  I2CStart(address, I2C_TRANSMITTER_MODE, I2C_ACK_ENABLE);
  I2CWriteData(reg);
  I2CStop();
  I2CStart(address, I2C_RECEIVER_MODE, I2C_ACK_ENABLE);
  for (i=0; i<count; i++) {
    if (i == (count - 1)) 
      data[i] = I2CReadNack(); //last byte
    else 
      data[i] = I2CReadAck();
  }
}

uint8_t Bcd2Bin(uint8_t bcd) {
  uint8_t dec;

  dec  = 10*(bcd>>4);
  dec += bcd&0x0F;
  return dec;
}
uint8_t Bin2Bcd(uint8_t bin) {
  uint8_t low = 0;
  uint8_t high = 0;
  
  //high nibble 
  high = bin/10;
  //low nibble 
  low = bin - (high*10); 
  return (high<<4 | low);
}

uint8_t CheckMinMax(uint8_t val, uint8_t min, uint8_t max) {
  if (val < min)
    return min;
  else if (val > max) 
    return max;
  return val;
}

void GetDateTime(DS3231_Time_t* time) {
  uint8_t data[7];
  
  //read multi bytes 
  I2CReadMulti(DS3231_ADDRESS, DS3231_SECONDS, data, 7);
  //fill data 
  time->seconds = Bcd2Bin(data[DS3231_SECONDS]);
  time->minutes = Bcd2Bin(data[DS3231_MINUTES]);
  time->hours = Bcd2Bin(data[DS3231_HOURS]);
  time->day = Bcd2Bin(data[DS3231_DAY]);
  time->date = Bcd2Bin(data[DS3231_DATE]);
  time->month = Bcd2Bin(data[DS3231_MONTH]);
  time->year = Bcd2Bin(data[DS3231_YEAR]);
}

void SetDateTime(DS3231_Time_t* time) {
  uint8_t data[7];
  
  //format data 
  data[DS3231_SECONDS] = Bin2Bcd(CheckMinMax(time->seconds, 0, 59));
  data[DS3231_MINUTES] = Bin2Bcd(CheckMinMax(time->minutes, 0, 59));
  data[DS3231_HOURS] = Bin2Bcd(CheckMinMax(time->hours, 0, 23));
  data[DS3231_DAY] = Bin2Bcd(CheckMinMax(time->day, 1, 7));
  data[DS3231_DATE] = Bin2Bcd(CheckMinMax(time->date, 1, 31));
  data[DS3231_MONTH] = Bin2Bcd(CheckMinMax(time->month, 1, 12));
  data[DS3231_YEAR] = Bin2Bcd(CheckMinMax(time->year, 0, 99));
  //write to device 
  I2CWriteMulti(DS3231_ADDRESS, DS3231_SECONDS, data, 7);
}

static __I uint8_t PrescTable[16] = { 0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9 };

uint32_t GetPclk1Freq(void) {
  uint32_t tmp = 0, presc = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
  uint32_t sysclk, hclk;

  //PLL_VCO = (HSE_VALUE or HSI_VALUE /PLLM)*PLLN 
  //SYSCLK = PLL_VCO/PLLP  
  pllsource = (RCC->PLLCFGR&RCC_PLLCFGR_PLLSRC)>>22;
  pllm = RCC->PLLCFGR&RCC_PLLCFGR_PLLM; 
  if (pllsource != 0)
    //HSE used as PLL clock source 
    pllvco = (16000000/pllm)*((RCC->PLLCFGR & RCC_PLLCFGR_PLLN)>>6);
  else
    //HSI used as PLL clock source 
    pllvco = (16000000/pllm)*((RCC->PLLCFGR&RCC_PLLCFGR_PLLN)>>6); 
  pllp = (((RCC->PLLCFGR&RCC_PLLCFGR_PLLP)>>16) + 1 )*2; 
  sysclk = pllvco/pllp;
  //get HCLK prescaler 
  tmp = RCC->CFGR&RCC_CFGR_HPRE;
  tmp = tmp>>4;
  presc = PrescTable[tmp];
  //HCLK clock frequency 
  hclk = sysclk>>presc;
  //get PCLK1 prescaler 
  tmp = RCC->CFGR&RCC_CFGR_PPRE1;
  tmp = tmp>>10;
  presc = PrescTable[tmp];
  //PCLK1 clock frequency 
  return (hclk>>presc);
}

//I2C_duty_cycle_in_fast_mode I2C duty cycle in fast mode  
#define I2C_DUTYCYCLE_2         ((uint32_t)0x00000000)
#define I2C_DUTYCYCLE_16_9      I2C_CCR_DUTY
//I2C_addressing_mode I2C addressing mode 
#define I2C_ADDRESSINGMODE_7BIT ((uint32_t)0x00004000)
//I2C_dual_addressing_mode  I2C dual addressing mode  
#define I2C_DUALADDRESS_DISABLE ((uint32_t)0x00000000)
#define I2C_DUALADDRESS_ENABLE  I2C_OAR2_ENDUAL
//I2C_general_call_addressing_mode I2C general call addressing mode  
#define I2C_GENERALCALL_DISABLE ((uint32_t)0x00000000)
#define I2C_GENERALCALL_ENABLE  I2C_CR1_ENGC
//I2C_nostretch_mode I2C nostretch mode  
#define I2C_NOSTRETCH_DISABLE   ((uint32_t)0x00000000)
#define I2C_NOSTRETCH_ENABLE    I2C_CR1_NOSTRETCH

uint32_t I2CSpeed(uint32_t pclk, uint32_t speed, uint32_t duty_cycle) {
  uint32_t i2c_speed, fast;

  if (duty_cycle == I2C_DUTYCYCLE_2) 
    fast = (pclk/(speed*3));
  else
    fast = ((pclk/(speed*25)) | I2C_DUTYCYCLE_16_9);
  if (speed <= 100000) {
    if (((pclk/(speed<<1))&I2C_CCR_CCR) < 4)
      i2c_speed = 4;
    else
      i2c_speed = (pclk/(speed<<1));
  } else if ((fast&I2C_CCR_CCR) == 0) 
    i2c_speed = 1;
  else
    i2c_speed = (fast | I2C_CCR_FS);
  return i2c_speed;
}

//setup i2c gpiob pins 6&7
void I2CGPIOInit(void) {
  uint32_t position;

  //enable gpiob peripheral clock
  RCC->AHB1ENR |= (1UL<<1);
  for (position=6; position<=7; position++) {
    //configure Alternate function mapped with the current IO 
    GPIOB->AFR[position>>3] &= ~((uint32_t)0xF<<((uint32_t)(position&(uint32_t)0x07)*4));
    GPIOB->AFR[position>>3] |= ((uint32_t)(GPIO_AF_I2C1)<<(((uint32_t)position&(uint32_t)0x07)*4));
    //configure IO Direction mode (Input, Output, Alternate or Analog) 
    GPIOB->MODER &= ~(((uint32_t)0x00000003)<<(position*2));
    GPIOB->MODER |= (GPIO_Mode_AF<<(position*2));
    //configure the IO Speed 
    GPIOB->OSPEEDR &= ~(((uint32_t)0x00000003)<<(position*2));
    GPIOB->OSPEEDR |= (GPIO_High_Speed<<(position*2));
    //configure the IO Output Type 
    GPIOB->OTYPER &= ~(((uint32_t)0x00000001)<<position) ;
    GPIOB->OTYPER |= (GPIO_OType_OD<<position);
    //activate the Pull-up or Pull down resistor for the current IO 
    GPIOB->PUPDR &= ~(((uint32_t)0x00000003)<<(position*2));
    GPIOB->PUPDR |= (GPIO_PuPd_UP<<(position*2));
  }
}

void ConfigureI2C1(void) {
  uint32_t freqrange = 0;
  uint32_t pclk1 = 0;

  //setup i2c gpio pins
  I2CGPIOInit();
  //enable i2c1 clock
  RCC->APB1ENR |= (1UL<<21);
  //disable the selected I2C peripheral 
  I2C1->CR1 &= ~I2C_CR1_PE;
  //get PCLK1 frequency 
  pclk1 = GetPclk1Freq();
  //calculate frequency range 
  freqrange = (pclk1/1000000);
  //configure I2C1 frequency range 
  I2C1->CR2 = freqrange;
  //configure I2C1 rise time:  if(I2CClockSpeed <= 100000) 
  if (100000 <= 100000) 
    I2C1->TRISE = freqrange + 1; 
  else
    I2C1->TRISE = ((freqrange*300)/1000) + 1;
  //configure I2C1 speed 
  //I2C1->CCR = SPEED(pclk1, 100000, I2C_DUTYCYCLE_2);
  I2C1->CCR = I2CSpeed(pclk1, 100000, I2C_DUTYCYCLE_2);
  //configure I2C1 Generalcall and NoStretch mode 
  I2C1->CR1 = (I2C_GENERALCALL_DISABLE | I2C_NOSTRETCH_DISABLE);
  //configure I2C1 Own Address1 and addressing mode 
  I2C1->OAR1 = (I2C_ADDRESSINGMODE_7BIT | 0);
  //configure I2C1 Dual mode and Own Address2 
  I2C1->OAR2 = (I2C_DUALADDRESS_DISABLE | 0);
  //enable the I2C peripheral 
  I2C1->CR1 |= I2C_CR1_PE;
}


//
//exti functions
//

//configure EXTI pin pb1
static void ConfigureEXTI(void) {
  uint8_t tmppriority = 0x00;
  uint8_t tmppre = 0x00;
  uint8_t tmpsub = 0x0F;

  //enable syscfg peripheral clock
  RCC->APB2ENR |= (1ul<<14);
  //enable GPIOB peripheral clock
  RCC->AHB1ENR |= (1ul<<1);                      
  //configure io direction
  GPIOB->MODER &= ~(((uint32_t)0x00000003)<<(1*2));
  GPIOB->MODER |= (GPIO_Mode_IN<<(1*2));
  //configure the io speed 
  GPIOB->OSPEEDR &= ~(((uint32_t)0x00000003)<<(1*2));
  GPIOB->OSPEEDR |= (GPIO_High_Speed<<(1*2));
  //configure the io output type 
  GPIOB->OTYPER &= ~(((uint32_t)0x00000001)<<1) ;
  GPIOB->OTYPER |= (GPIO_OType_PP<<1);
  //activate pull-up or pull-down resistor 
  GPIOB->PUPDR &= ~(((uint32_t)0x00000003)<<(1*2));
  GPIOB->PUPDR |= (GPIO_PuPd_UP<<(1*2));

  //SYSCFG_EXTILineConfig
  SYSCFG->EXTICR[(uint8_t)1>0x02] &= ~(((uint32_t)0x0F)<<(0x04*((uint8_t)1&(uint8_t)0x03)));
  SYSCFG->EXTICR[(uint8_t)1>>0x02] |= (((uint32_t)(uint8_t)1)<<(0x04*((uint8_t)1&(uint8_t)0x03)));

  //EXTI_Init
  //clear EXTI line configuration 
  EXTI->IMR &= ~EXTI_Line1;
  EXTI->EMR &= ~EXTI_Line1;
  *(__IO uint32_t *)((uint32_t)EXTI_BASE + EXTI_Mode_Interrupt) |= EXTI_Line1;
  //clear Rising/Falling edge configuration 
  EXTI->RTSR &= ~EXTI_Line1;
  EXTI->FTSR &= ~EXTI_Line1;
  //select trigger for the selected external interrupt 
  *(__IO uint32_t *)((uint32_t)EXTI_BASE + EXTI_Trigger_Rising) |= EXTI_Line1;

  //add IRQ vector to NVIC: NVIC_Init
  //compute the corresponding IRQ priority
  tmppriority = (0x700 - ((SCB->AIRCR)&(uint32_t)0x700))>>0x08;
  tmppre = (0x4 - tmppriority);
  tmpsub = tmpsub>>tmppriority;
  tmppriority = 0<<tmppre;
  tmppriority |= (uint8_t)(1&tmpsub);
  tmppriority = tmppriority<<0x04;
  NVIC->IP[EXTI1_IRQn] = tmppriority;
  //enable selected IRQ channel
  NVIC->ISER[EXTI1_IRQn>>0x05] = (uint32_t)0x01<<(EXTI1_IRQn&(uint8_t)0x1F);
}

//led heartbeat: external pin interrupt (pb1) driven by DS3231 1Hz square wave
void EXTI1_IRQHandler(void) {
  //check interrupt flag set 
  if ((EXTI->PR&EXTI_Line1) != (uint32_t)RESET) {
    //toggle led
    GPIOA->ODR ^= GPIO_Pin_5;
    //clear interrupt flag 
    EXTI->PR = EXTI_Line1;
  }
}


//
//main program loop
//
int main(void) {
  char str[100];
  DS3231_Time_t time;

  //configure system clock
  SystemCoreClockConfigure();                              
  SystemCoreClockUpdate();

  //configure nucleo led & button
  ConfigureNucleoGPIOs();
  
  //config exti
  ConfigureEXTI();
  
  //configure i2c
  ConfigureI2C1();

  //init vcomm port
  SER_Initialize();
  
  //set DS3231 date and time 
  time.hours = 21;
  time.minutes = 02;
  time.seconds = 4;
  time.date = 5;
  time.day = 4;
  time.month = 11;
  time.year = 15;
  SetDateTime(&time);

  //set DS3231 SQW to 1Hz
  I2CWrite(DS3231_ADDRESS, DS3231_CONTROL_REG, 0x00);

  while (1) {
    uint32_t i;
    
    //button pressed?
    if((GPIOC->IDR & GPIO_Pin_13) == (uint32_t)Bit_RESET) {
      //get date and time 
      GetDateTime(&time);
      //display 
      sprintf(str, "Day: %d\nDate: %02d\nMonth: %02d\nYear: %04d\nHours: %02d\nMinutes: %02d\nSeconds: %02d", time.day, time.date, time.month, time.year + 2000, time.hours, time.minutes, time.seconds);
      SER_OutString(str);
      //approximately 1-second delay for button debounce
      for(i=0; i<0x7fffff; i++)
        __NOP();
    }
  }
}
Advertisements

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s