#include "main.h" #define RTC_TX_BUF_SIZE 4 extern int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len); extern int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len); static uint8_t i2cBufTX[RTC_TX_BUF_SIZE] = {0}; /** * @brief Инициализация RTC */ void RTC_Init(void) { uint8_t buf[3] = {0}; /* Clear flags */ Flag.I2C_TX_End = 0; buf[0] = DS3231_1HZ; // set 1 Hz output squware buf[1] = 0x0; // disable 32 kHz output user_i2c_write(DS3231_I2C_ADDR, DS3231_ADDR_CONTROL, buf, 2); } void test_w(rtc_t * data) { /* Source: Address of the I2C TX buffer. */ DMA1_Channel3->CMAR = (uint32_t)&i2cBufTX; /* Destination: I2C TX data register. */ DMA1_Channel3->CPAR = (uint32_t)&(I2C1->TXDR); /* Set DMA data transfer length (I2C TX buffer length). */ DMA1_Channel3->CNDTR = 3; // hardcode / magic number /* Enable DMA channels for I2C */ DMA1_Channel3->CCR |= DMA_CCR_EN; /* Fill buffer with register address and register value */ i2cBufTX[0] = DS3231_ADDR_CONTROL; i2cBufTX[1] = DS3231_1HZ; // set 1 Hz output squware i2cBufTX[2] = 0x0; // disable 32 kHz output /* Wait for I2C */ while ( I2C1->ISR & I2C_ISR_BUSY ) {}; /* Set the device address and number bytes to send. */ I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | 3 << I2C_CR2_NBYTES_Pos ); /* Enable I2C DMA requests. */ I2C1->CR1 |= ( I2C_CR1_TXDMAEN ); /* Send a start signal. */ I2C1->CR2 |= ( I2C_CR2_START ); /* (DMA is now running.) */ } /** * @brief Чтение всех регистров DS3231 */ void RTC_ReadAll(rtc_t * data) { Flag.I2C_RX_End = 0; Flag.I2C_TX_End = 0; user_i2c_read(DS3231_I2C_ADDR, DS3231_ADDR_TIME, (uint8_t *)data, DS3231_SIZE_ALL); } void test_r(rtc_t * data) { /* Source: Address of the I2C RX buffer. */ DMA1_Channel2->CMAR = (uint32_t)data; /* Destination: I2C RX data register. */ DMA1_Channel2->CPAR = (uint32_t)&(I2C1->RXDR); /* Set DMA data transfer length (I2C RX buffer length). */ DMA1_Channel2->CNDTR = DS3231_SIZE_ALL; /* Enable DMA channels for I2C RX */ DMA1_Channel2->CCR |= DMA_CCR_EN; /* wait for i2c */ while ( I2C1->ISR & I2C_ISR_BUSY ) {}; /* send first register address 00h */ I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | 1 << I2C_CR2_NBYTES_Pos ); I2C1->CR2 |= ( I2C_CR2_START ); while ( !( I2C1->CR2 & I2C_CR2_START ) ) {}; I2C1->TXDR = DS3231_ADDR_TIME; while ( I2C1->ISR & I2C_ISR_BUSY ) {}; /* Reading all */ I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | DS3231_SIZE_ALL << I2C_CR2_NBYTES_Pos | I2C_CR2_RD_WRN); I2C1->CR1 |= ( I2C_CR1_RXDMAEN ); I2C1->CR2 |= ( I2C_CR2_START ); } /** * @brief Запись времени и календаря */ void RTC_WriteTimeCalendar(rtc_t * data) { Flag.I2C_TX_End = 0; DMA1_Channel3->CCR &= ~DMA_CCR_EN; DMA1_Channel3->CMAR = (uint32_t)data; DMA1_Channel3->CPAR = (uint32_t)&(I2C1->TXDR); DMA1_Channel3->CNDTR = DS3231_SIZE_TIME + DS3231_SIZE_CALENDAR; while ( I2C1->ISR & I2C_ISR_BUSY ) {}; I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | (DS3231_SIZE_TIME + DS3231_SIZE_CALENDAR + 1) << I2C_CR2_NBYTES_Pos ); I2C1->CR1 |= ( I2C_CR1_TXDMAEN ); I2C1->CR2 |= ( I2C_CR2_START ); while ( !( I2C1->CR2 & I2C_CR2_START ) ) {}; I2C1->TXDR = DS3231_ADDR_TIME; // send reg addr when START finish DMA1_Channel3->CCR |= DMA_CCR_EN; // and launch DMA for data to transfer } /** * @brief Запись времени */ void RTC_WriteTime(rtc_t * data) { Flag.I2C_TX_End = 0; DMA1_Channel3->CMAR = (uint32_t)data; DMA1_Channel3->CPAR = (uint32_t)&(I2C1->TXDR); DMA1_Channel3->CNDTR = DS3231_SIZE_TIME; while ( I2C1->ISR & I2C_ISR_BUSY ) {}; I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | (DS3231_SIZE_TIME + 1) << I2C_CR2_NBYTES_Pos ); I2C1->CR1 |= ( I2C_CR1_TXDMAEN ); I2C1->CR2 |= ( I2C_CR2_START ); while ( !( I2C1->CR2 & I2C_CR2_START ) ) {}; I2C1->TXDR = DS3231_ADDR_TIME; DMA1_Channel3->CCR |= DMA_CCR_EN; } /** * @brief Запись часов */ void RTC_WriteHH(rtc_t * data) { Flag.I2C_TX_End = 0; // некому установить этот флаг в 1 while ( I2C1->ISR & I2C_ISR_BUSY ) {}; I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | 2 << I2C_CR2_NBYTES_Pos ); I2C1->CR2 |= ( I2C_CR2_START ); while ( !( I2C1->CR2 & I2C_CR2_START ) ) {}; I2C1->TXDR = (DS3231_ADDR_TIME + 2); while ((I2C1->ISR & I2C_ISR_TXE) == 0) { __NOP(); }; I2C1->TXDR = data->Hr; } /** * @brief Запись часов и минут */ void RTC_WriteHHMM(rtc_t * data) { Flag.I2C_TX_End = 0; DMA1_Channel3->CMAR = (uint32_t)&i2cBufTX; DMA1_Channel3->CPAR = (uint32_t)&(I2C1->TXDR); DMA1_Channel3->CNDTR = 3; // addr + mm + hh DMA1_Channel3->CCR |= DMA_CCR_EN; /* Fill buffer with register address and register value */ i2cBufTX[0] = DS3231_ADDR_TIME + 1; // skip seconds i2cBufTX[1] = data->Min; i2cBufTX[2] = data->Hr; while ( I2C1->ISR & I2C_ISR_BUSY ) {}; I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | 3 << I2C_CR2_NBYTES_Pos ); I2C1->CR1 |= ( I2C_CR1_TXDMAEN ); I2C1->CR2 |= ( I2C_CR2_START ); } /** * @brief Запись календаря */ void RTC_WriteCalendar(rtc_t * data) { Flag.I2C_TX_End = 0; DMA1_Channel3->CMAR = (uint32_t)&(data->WD); DMA1_Channel3->CPAR = (uint32_t)&(I2C1->TXDR); DMA1_Channel3->CNDTR = DS3231_SIZE_CALENDAR; while ( I2C1->ISR & I2C_ISR_BUSY ) {}; I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN); I2C1->CR2 |= ( DS3231_I2C_ADDR | (DS3231_SIZE_CALENDAR + 1) << I2C_CR2_NBYTES_Pos ); I2C1->CR1 |= ( I2C_CR1_TXDMAEN ); I2C1->CR2 |= ( I2C_CR2_START ); while ( !( I2C1->CR2 & I2C_CR2_START ) ) {}; I2C1->TXDR = DS3231_ADDR_CALENDAR; DMA1_Channel3->CCR |= DMA_CCR_EN; } /** * @brief Convert BCD value to Binary */ uint8_t bcd2bin(uint8_t bcd) { return (10 * (bcd >> 4) + (bcd & 0x0f)); } /** * @brief Convert Binary value to BCD */ uint8_t bin2bcd(uint8_t bin) { return (((bin / 10 ) << 4) | (bin % 10)); }