소스 검색

Added I2C and RTC routines.

Vladimir N. Shilov 2 년 전
부모
커밋
a8bccb6f16
10개의 변경된 파일529개의 추가작업 그리고 10개의 파일을 삭제
  1. 2 0
      Makefile
  2. 56 0
      inc/digits.h
  3. 106 0
      inc/ds3231.h
  4. 25 0
      inc/i2c.h
  5. 7 3
      inc/main.h
  6. 6 6
      src/board.c
  7. 144 0
      src/ds3231.c
  8. 148 0
      src/i2c.c
  9. 30 1
      src/main.c
  10. 5 0
      src/rtos.c

+ 2 - 0
Makefile

@@ -36,6 +36,8 @@ SRCS = \
   main.c \
   board.c \
   rtos.c \
+  i2c.c \
+  ds3231.c \
   system_stm32f0xx.c
  
 SRCSASM = startup_stm32f030x6.s

+ 56 - 0
inc/digits.h

@@ -0,0 +1,56 @@
+/**
+ * Digits 4x7 px normal
+ * Digits 4x7 px 7-segment style
+ * font for screen based on HT1632C
+ * Vladimir N. Shilov shilow@ukr.net
+ */
+
+#pragma once
+#ifndef _DIGITS_H
+#define _DIGITS_H
+
+/*
+ ##    #   ##   ##     # ####  ##  ####  ##   ## 
+#  #  ##  #  # #  #   ## #    #  #    # #  # #  #  ##
+#  #   #    #     #  # # #    #      #  #  # #  #  ##
+#  #   #   #    ##  #### ###  ###   #    ##   ###
+#  #   #  #       #    #    # #  #  #   #  #    #  ##
+#  #   #  #    #  #    # #  # #  #  #   #  # #  #  ##
+ ##   ### ####  ##     #  ##   ##   #    ##   ## 
+*/
+static const uint8_t digit_4x7[11][4] = {
+  {0x3e, 0x41, 0x41, 0x3e},
+  {0x00, 0x42, 0x7f, 0x40},
+  {0x72, 0x49, 0x45, 0x42},
+  {0x22, 0x49, 0x49, 0x36},
+  {0x08, 0x0c, 0x0a, 0x7f},
+  {0x2f, 0x49, 0x49, 0x31},
+  {0x3e, 0x49, 0x49, 0x32},
+  {0x01, 0x79, 0x05, 0x03},
+  {0x36, 0x49, 0x49, 0x36},
+  {0x26, 0x49, 0x49, 0x3e},
+  {0x00, 0x36, 0x36, 0x00}
+};
+
+/*
+ ##         ##    ##          ##    ##    ##    ##    ## 
+#  #    #     #     #  #  #  #     #        #  #  #  #  #
+#  #    #     #     #  #  #  #     #        #  #  #  #  #
+            ##    ##    ##    ##    ##          ##    ## 
+#  #    #  #        #     #     #  #  #     #  #  #     #
+#  #    #  #        #     #     #  #  #     #  #  #     #
+ ##         ##    ##          ##    ##          ##    ## 
+*/
+static const uint8_t digit_7seg[10][4] = {
+  {0x36, 0x41, 0x41, 0x36},
+  {0x00, 0x00, 0x00, 0x36},
+  {0x30, 0x49, 0x49, 0x06},
+  {0x00, 0x49, 0x49, 0x36},
+  {0x06, 0x08, 0x08, 0x36},
+  {0x06, 0x49, 0x49, 0x30},
+  {0x36, 0x49, 0x49, 0x30},
+  {0x00, 0x01, 0x01, 0x36},
+  {0x36, 0x49, 0x49, 0x36},
+  {0x06, 0x49, 0x49, 0x36}
+};
+#endif /* _DIGITS_H */

+ 106 - 0
inc/ds3231.h

@@ -0,0 +1,106 @@
+#pragma once
+#ifndef DS3231_H
+#define DS3231_H
+
+/* RTC Status */
+typedef enum {
+  RTC_OK  = 0x00,
+  RTC_TWI_TimeOut,
+  RTC_TWI_Error
+} rtc_status_t;
+
+/**
+ * @brief   Clock sructure.
+ * @note    structure of ds3231 data.
+ */
+typedef struct {
+  /**
+   * @brief  00h: Seconds
+   */
+  uint8_t Sec;
+  /**
+   * @brief  01h: Minutes
+   */
+  uint8_t Min;
+  /**
+   * @brief  02h: Hours
+   */
+  uint8_t Hr;
+  /**
+   * @brief  03h: Week Day
+   */
+  uint8_t WD;
+  /**
+   * @brief  04h: Day of Month
+   */
+  uint8_t Day;
+  /**
+   * @brief  05h: Month
+   */
+  uint8_t Mon;
+  /**
+   * @brief  06h: Year
+   */
+  uint8_t Year;
+  /**
+   * @brief  07h: Alarm 1 Seconds
+   */
+  uint8_t A1SS;
+  /**
+   * @brief  08h: Alarm 1 Minutes
+   */
+  uint8_t A1MM;
+  /**
+   * @brief  09h: Alarm 1 Hours
+   */
+  uint8_t A1HH;
+  /**
+   * @brief  0Ah: Alarm 1 Day / Date
+   */
+  uint8_t A1DD;
+  /**
+   * @brief  0Bh: Alarm 2 Minutes
+   */
+  uint8_t A2MM;
+  /**
+   * @brief  0Ch: Alarm 2 Hours
+   */
+  uint8_t A2HH;
+  /**
+   * @brief  0Dh: Alarm 2 Day  / Date
+   */
+  uint8_t A2DD;
+  /**
+   * @brief  0Eh: Control
+   */
+  uint8_t Ctrl;
+  /**
+   * @brief  0Fh: Control/Status
+   */
+  uint8_t CtSt;
+  /**
+   * @brief  10h: Aging Offset
+   */
+  uint8_t AgOffset;
+  /**
+   * @brief  11h: MSB of Temp
+   */
+  uint8_t TempH;
+  /**
+   * @brief  12h: LSB of Temp
+   */
+  uint8_t TempL;
+} rtc_t;
+
+void RTC_Init(void);
+void RTC_ReadAll(rtc_t * data);
+void RTC_ReadTime(rtc_t * data);
+void RTC_WriteTimeCalendar(rtc_t * data);
+void RTC_WriteTime(rtc_t * data);
+void RTC_WriteHHMM(rtc_t * data);
+void RTC_WriteCalendar(rtc_t * data);
+
+uint8_t bcd2bin(uint8_t bcd);
+uint8_t bin2bcd(uint8_t bin);
+
+#endif // DS3231_H

+ 25 - 0
inc/i2c.h

@@ -0,0 +1,25 @@
+#pragma once
+#ifndef _I2C_H_
+#define _I2C_H_
+
+/* Includes */
+#include "main.h"
+
+/* Exported typedefs */
+/** @brief I2C return Status */
+typedef enum i2c_status {
+  I2C_Ret_OK  = 0,
+  I2C_Ret_NACK = 1,
+  I2C_Ret_Bsy  = 2,
+  I2C_Ret_Tout = 3,
+  I2C_Ret_Err = 4
+} i2c_status_t;
+
+/* Exported variabless */
+extern uint32_t I2C_tout; 
+
+/* Exported function prototypes */
+i2c_status_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);
+i2c_status_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);
+
+#endif /* _I2C_H_ */

+ 7 - 3
inc/main.h

@@ -22,8 +22,8 @@ extern "C" {
 /* Private includes ----------------------------------------------------------*/
 #include "board.h"
 #include "rtos.h"
-//#include "i2c.h"
-//#include "ds3231.h"
+#include "i2c.h"
+#include "ds3231.h"
 //#include "event-system.h"
 //#include "list_event.h"
 //#include "clock.h"
@@ -41,7 +41,11 @@ typedef enum {
 
 typedef struct t_flag {
   uint32_t RTC_IRQ:     1;
-  uint32_t _reserv:    31;
+  uint32_t I2C_TX_Err:  1;
+  uint32_t I2C_TX_End:  1;
+  uint32_t I2C_RX_Err:  1;
+  uint32_t I2C_RX_End:  1;
+  uint32_t _reserv:    27;
 } flag_t;
 extern volatile flag_t Flag;
 

+ 6 - 6
src/board.c

@@ -213,7 +213,7 @@ static void I2C1_Init(void)
   NVIC_EnableIRQ(I2C1_IRQn);
 
   /** I2C Initialization: I2C_Fast */
-  I2C1->CR1 = (I2C_CR1_TXDMAEN | I2C_CR1_RXIE); //  | I2C_CR1_ERRIE
+  I2C1->CR1 = (I2C_CR1_TXDMAEN); //  | I2C_CR1_RXIE | I2C_CR1_ERRIE
   I2C1->TIMINGR = 0x00701850; // 400 kHz / 48 MHz / 50 ns / 50 ns
   I2C1->CR2 = I2C_CR2_AUTOEND;
   I2C1->CR1 |= I2C_CR1_PE;
@@ -359,7 +359,7 @@ void _display_WriteBits(const uint16_t data, uint16_t nbits) {
 }
 
 /**
- * @brief Write Data to HT1632C
+ * @brief Write Data to display buffer, no transfer to HT1632.
  * @param data pointer to data array
  * @param addr begin address
  * @param len bytes to write
@@ -383,7 +383,7 @@ void display_WriteData(const uint8_t * data, uint8_t addr, uint8_t len) {
     a = addr + i;
     display_Buffer[a] = data[i];
   }
-  display_WriteBuffer();
+  //display_WriteBuffer();
 #else
   uint16_t a = 0x280 | addr;
 
@@ -525,14 +525,14 @@ void DMA1_Channel2_3_IRQHandler(void) {
     DMA1->IFCR = DMA_IFCR_CTCIF2;
     // Disable DMA channels for I2C TX
     DMA1_Channel2->CCR &= ~(DMA_CCR_EN);
-    //Flag.I2C_TX_End = 1;
+    Flag.I2C_TX_End = 1;
   }
   // I2C Transmit Error
   if ((DMA1->ISR & DMA_ISR_TEIF2) != 0) {
     DMA1->IFCR = DMA_IFCR_CTEIF2;
     DMA1_Channel2->CCR &= ~(DMA_CCR_EN);
-    //Flag.I2C_RX_End = 1;
-    //Flag.I2C_RX_Err = 1;
+    Flag.I2C_TX_End = 1;
+    Flag.I2C_TX_Err = 1;
   }
 }
 

+ 144 - 0
src/ds3231.c

@@ -0,0 +1,144 @@
+#include "main.h"
+
+/* Private defines & macro */
+/* i2c slave address of the DS3231 chip */
+#define DS3231_I2C_ADDR             0xD0
+
+/* timekeeping registers */
+#define DS3231_ADDR_TIME            0x00
+#define DS3231_ADDR_CALENDAR        0x03
+#define DS3231_ADDR_ALARM1          0x07
+#define DS3231_ADDR_ALARM2          0x0B
+#define DS3231_ADDR_CONTROL         0x0E
+#define DS3231_ADDR_STATUS          0x0F
+#define DS3231_ADDR_AGING_OFFSET    0x10
+#define DS3231_ADDR_TEMPERATURE     0x11
+
+/* control register bits */
+#define DS3231_A1IE                 0x01
+#define DS3231_A2IE                 0x02
+#define DS3231_INTCN                0x04
+#define DS3231_RS1	                0x08
+#define DS3231_RS2	                0x10
+#define DS3231_CONV	                0x20
+#define DS3231_BBSQW	              0x40
+#define DS3231_OSC_OSC	            0x80
+
+/* control/status register bits */
+#define DS3231_A1F                  0x01
+#define DS3231_A2F                  0x02
+#define DS3231_BSY                  0x04
+#define DS3231_EN32kHz              0x08
+#define DS3231_OSF                  0x80
+
+/* square-wave output frequency */
+#define DS3231_1HZ	                0x00
+#define DS3231_1024HZ	              DS3231_RS1
+#define DS3231_4096HZ	              DS3231_RS2
+#define DS3231_8192HZ	              (DS3231_RS1 | DS3231_RS2)
+
+/* number of bytes */
+#define DS3231_SIZE_TIME            3
+#define DS3231_SIZE_CALENDAR        4
+#define DS3231_SIZE_ALARM1          4
+#define DS3231_SIZE_ALARM2          3
+#define DS3231_SIZE_CONTROL         1
+#define DS3231_SIZE_STATUS          1
+#define DS3231_SIZE_AGOFFS          1
+#define DS3231_SIZE_TEMPERATURE     2
+#define DS3231_SIZE_ALL             19
+
+/**
+ * @brief Initialization DS3231
+ */
+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);
+}
+
+/**
+ * @brief Reading all registers 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);
+}
+
+/**
+ * @brief Read Time "SS:MM:HH"
+ */
+void RTC_ReadTime(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_read(DS3231_I2C_ADDR, DS3231_ADDR_TIME, &(data->Sec), DS3231_SIZE_TIME);
+}
+
+/**
+ * @brief Save time and calendar "SS:MM:HH wd dd/mm/yy"
+ */
+void RTC_WriteTimeCalendar(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_write(DS3231_I2C_ADDR, DS3231_ADDR_TIME, &(data->Sec), (DS3231_SIZE_TIME + DS3231_SIZE_CALENDAR));
+}
+
+/**
+ * @brief Save Time "SS:MM:HH"
+ */
+void RTC_WriteTime(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_write(DS3231_I2C_ADDR, DS3231_ADDR_TIME, &(data->Sec), DS3231_SIZE_TIME);
+}
+
+/**
+ * @brief Save hours "HH"
+ */
+void RTC_WriteHH(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_write(DS3231_I2C_ADDR, (DS3231_ADDR_TIME + 2), &(data->Hr), 1);
+}
+
+/**
+ * @brief Save hours & minutes "MM:HH"
+ */
+void RTC_WriteHHMM(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_write(DS3231_I2C_ADDR, (DS3231_ADDR_TIME + 1), &(data->Min), 2);
+}
+
+/**
+ * @brief Save calendar "wd dd/mm/yy"
+ */
+void RTC_WriteCalendar(rtc_t * data) {
+  Flag.I2C_TX_End = 0;
+
+  user_i2c_write(DS3231_I2C_ADDR, DS3231_ADDR_CALENDAR, &(data->WD), DS3231_SIZE_CALENDAR);
+}
+
+/**
+ * @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));
+}

+ 148 - 0
src/i2c.c

@@ -0,0 +1,148 @@
+/**
+  ******************************************************************************
+  * @file           : i2c.c
+  * @brief          : I2C base functions
+  ******************************************************************************
+  */
+
+#include "main.h"
+
+/* Private variables */
+uint32_t I2C_tout = 0;
+static i2c_status_t st_Read = I2C_Ret_OK;
+
+/* Private function prototypes */
+i2c_status_t i2c_check_err(void);
+
+/**
+ * @brief Check I2C bus for errors.
+ * @retval I2C return code
+ */
+i2c_status_t i2c_check_err(void) {
+  i2c_status_t r = I2C_Ret_OK;
+
+  if ((I2C1->ISR & I2C_ISR_NACKF) != 0) {
+  /* device not present */
+    r = I2C_Ret_NACK;
+  } else if ((I2C1->ISR & I2C_ISR_TIMEOUT) != 0) {
+  /* timeout error */
+    r = I2C_Ret_Tout;
+  } else if ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR)) != 0) {
+  /* other error */
+    r = I2C_Ret_Err;
+  }
+
+  if (r != I2C_Ret_OK) {
+  /* restart I2C and clear flags */
+    I2C1->CR1 &= ~I2C_CR1_PE;
+    while ((I2C1->CR1 & I2C_CR1_PE) != 0);
+    I2C1->CR1 |= I2C_CR1_PE;
+  }
+
+  return r;
+}
+
+/**
+ * @brief Read len bytes from I2C bus to data by reg_addr.
+ * @retval I2C return code
+ */
+i2c_status_t user_i2c_read(const uint8_t id, const uint8_t reg_addr, uint8_t *data, const uint16_t len) {
+  st_Read = I2C_Ret_OK;
+
+  Flag.I2C_RX_End = 0;
+  Flag.I2C_RX_Err = 0;
+  Flag.I2C_TX_Err = 0;
+
+  /* wait for i2c */
+  while ( I2C1->ISR & I2C_ISR_BUSY ) { __NOP(); };
+
+  /* prepare i2c for sending reg addr */
+  I2C1->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
+  I2C1->CR2 |= (id | 1 << I2C_CR2_NBYTES_Pos);
+  /* gen START */
+  I2C1->CR2 |= I2C_CR2_START;
+
+  /* wait for byte request or any error */
+  while ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) { __NOP(); };
+
+  if ((I2C1->ISR & I2C_ISR_TXE) != 0) {
+  /* device ok, send reg addr */
+    I2C1->TXDR = reg_addr;
+  } else {
+    st_Read = i2c_check_err();
+    if (st_Read != I2C_Ret_OK) {
+      Flag.I2C_TX_Err = 1;
+      return st_Read;
+    }
+  }
+
+  /* wait for i2c or any error */
+  while (((I2C1->ISR & I2C_ISR_BUSY) != 0) && ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF)) == 0)) { __NOP(); };
+  st_Read = i2c_check_err();
+  if (st_Read != I2C_Ret_OK) {
+    Flag.I2C_TX_Err = 1;
+    return st_Read;
+  }
+
+  int cnt = 0;
+  // Read data while no TC flag set.
+  // Если взлетит NACK-флаг, приём прекращаем.
+  while ((((I2C1->ISR & I2C_ISR_TC)==0) && ((I2C1->ISR & I2C_ISR_NACKF)==0)) && (I2C1->ISR & I2C_ISR_BUSY)) {
+    if (I2C1->ISR & I2C_ISR_RXNE) { // Reading data
+      *data = I2C1->RXDR;
+      data ++;
+      cnt ++;
+      if (cnt > len) {
+        st_Read = I2C_Ret_Err;
+        break;
+      }
+    }
+  }
+
+  /* wait for receiving data */
+//  while ((Flag.I2C_RX_End == 0) && (Flag.I2C_RX_Err == 0)) { __NOP(); };
+
+  /* Set STOP */
+  //I2C1->CR2 |= I2C_CR2_STOP;
+  /* Clear flags */
+  //I2C1->ICR = (I2C_ICR_STOPCF | I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF);
+
+  return st_Read;
+}
+
+/**
+ * @brief Write len bytes to I2C bus from data by reg_addr.
+ * @retval I2C return code
+ */
+i2c_status_t user_i2c_write(const uint8_t id, const uint8_t reg_addr, uint8_t *data, const uint16_t len) {
+  i2c_status_t r = I2C_Ret_OK;
+
+  Flag.I2C_TX_End = 0;
+  Flag.I2C_TX_Err = 0;
+
+  DMA1_Channel2->CMAR = (uint32_t)data;
+  DMA1_Channel2->CPAR = (uint32_t)&(I2C1->TXDR);
+  DMA1_Channel2->CNDTR = len;
+
+  while ( I2C1->ISR & I2C_ISR_BUSY );
+
+  I2C1->CR2 &= ~( I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RD_WRN);
+  I2C1->CR2 |= ( id | (len + 1) << I2C_CR2_NBYTES_Pos );
+  I2C1->CR2 |= ( I2C_CR2_START );
+
+  while ((I2C1->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR | I2C_ISR_NACKF | I2C_ISR_TXE)) == 0) { __NOP(); };
+  if ((I2C1->ISR & I2C_ISR_TXE) != 0) {
+    I2C1->TXDR = reg_addr;
+  } else {
+    r = i2c_check_err();
+    if (r != I2C_Ret_OK) {
+      Flag.I2C_TX_Err = 1;
+      return r;
+    }
+  }
+
+  DMA1_Channel2->CCR |= DMA_CCR_EN;
+  I2C1->CR1 |= I2C_CR1_TXDMAEN;
+
+  return r;
+}

+ 30 - 1
src/main.c

@@ -10,14 +10,18 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "main.h"
+#include "digits.h"
 
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 /* Private macro -------------------------------------------------------------*/
 /* Private variables ---------------------------------------------------------*/
 volatile flag_t Flag = {0};
+static rtc_t Clock;
 
 /* Private function prototypes -----------------------------------------------*/
+static void Show_MMSS(void);
+
 /* Private functions ---------------------------------------------------------*/
 
 /**
@@ -32,14 +36,23 @@ int main(void)
 
   /* Initialize Scheduler */
   RTOS_Init();
+//  RTOS_SetTask(Show_MMSS, 1000, 1000);
+
+  /* Real-Time clock */
+  RTC_Init();
+  RTC_ReadTime(&Clock);
 
-  display_test();
+  display_Init();
+  display_Buffer[11] = 0x36;
+  display_Buffer[12] = 0x36;
 
   /* Infinite loop */
   while (1)
   {
     if (Flag.RTC_IRQ != 0) {
       Flag.RTC_IRQ = 0;
+      RTC_ReadTime(&Clock);
+      Show_MMSS();
     }
 
     RTOS_DispatchTask();
@@ -48,6 +61,22 @@ int main(void)
   }
 }
 
+static void Show_MMSS(void) {
+  uint8_t t;
+
+  t = Clock.Min >> 4;
+  display_WriteData(&digit_4x7[t][0], 1, 4);
+
+  t = Clock.Min | 0xf;
+  display_WriteData(&digit_4x7[t][0], 6, 4);
+
+  t = Clock.Sec >> 4;
+  display_WriteData(&digit_4x7[t][0], 14, 4);
+
+  t = Clock.Sec | 0xf;
+  display_WriteData(&digit_4x7[t][0], 19, 4);
+}
+
 /******************************************************************************/
 /*            Cortex-M0 Processor Exceptions Handlers                         */
 /******************************************************************************/

+ 5 - 0
src/rtos.c

@@ -186,4 +186,9 @@ void SysTick_Handler(void) {
   if (TDelay != 0) {
     TDelay --;
   }
+
+  /* decrement i2c counter */
+  if (I2C_tout != 0) {
+    I2C_tout --;
+  }
 }