ISKBoard example project
guowenxue
5 days ago 1105733dc07562240bd061a1d8b0869c8c596805
ISL1208 RTC示例程序
2 files added
1 files modified
410 ■■■■■ changed files
Core/Src/board/isl1208.c 343 ●●●●● patch | view | raw | blame | history
Core/Src/board/isl1208.h 46 ●●●●● patch | view | raw | blame | history
Core/Src/main.c 21 ●●●● patch | view | raw | blame | history
Core/Src/board/isl1208.c
New file
@@ -0,0 +1,343 @@
/**********************************************************************
 *   Copyright: (C)2024 LingYun IoT System Studio
 *      Author: GuoWenxue<guowenxue@gmail.com>
 *
 * Description: ISL1208 RTC driver on ISKBoard
 *
 *   ChangeLog:
 *        Version    Date       Author            Description
 *        V1.0.0  2024.08.29    GuoWenxue      Release initial version
 *
 ***********************************************************************/
#include <stdio.h>
#include <string.h>
#include "isl1208.h"
#include "i2c_bitbang.h"
//#define CONFIG_DEBUG_RTC /* Enable ISL1208 RTC debug */
#define ISL1208_CHIPADDR        0x6F      /* ISL1208 7-Bits Chip address */
#ifdef  CONFIG_DEBUG_RTC
#define rtc_print(format,args...) printf(format, ##args)
#else
#define rtc_print(format,args...) do{} while(0)
#endif
/*+--------------------------------------+
 *|      RTC Chipset ISL1208 Register    |
 *+--------------------------------------+*/
/* rtc section */
#define ISL1208_REG_SC          0x00
#define ISL1208_REG_MN          0x01
#define ISL1208_REG_HR          0x02
#define ISL1208_REG_HR_MIL     (1<<7)   /* 24h/12h mode */
#define ISL1208_REG_HR_PM      (1<<5)   /* PM/AM bit in 12h mode */
#define ISL1208_REG_DT          0x03
#define ISL1208_REG_MO          0x04
#define ISL1208_REG_YR          0x05
#define ISL1208_REG_DW          0x06
#define ISL1208_RTC_SECTION_LEN 7 /* RTC Section register */
#define REGS_RTC_SR_LEN         8 /* RTC Section and status register  */
/* control/status section */
#define ISL1208_REG_SR          0x07
#define ISL1208_REG_SR_ARST    (1<<7)   /* auto reset */
#define ISL1208_REG_SR_XTOSCB  (1<<6)   /* crystal oscillator */
#define ISL1208_REG_SR_WRTC    (1<<4)   /* write rtc */
#define ISL1208_REG_SR_EVT     (1<<3)   /* event */
#define ISL1208_REG_SR_ALM     (1<<2)   /* alarm */
#define ISL1208_REG_SR_BAT     (1<<1)   /* battery */
#define ISL1208_REG_SR_RTCF    (1<<0)   /* rtc fail */
#define ISL1208_REG_INT         0x08
#define ISL1208_REG_INT_ALME   (1<<6)   /* alarm enable */
#define ISL1208_REG_INT_IM     (1<<7)   /* interrupt/alarm mode */
#define ISL1219_REG_EV          0x09
#define ISL1219_REG_EV_EVEN    (1<<4)   /* event detection enable */
#define ISL1219_REG_EV_EVIENB  (1<<7)   /* event in pull-up disable */
#define ISL1208_REG_ATR         0x0a
#define ISL1208_REG_DTR         0x0b
/* alarm section */
#define ISL1208_REG_SCA         0x0c
#define ISL1208_REG_MNA         0x0d
#define ISL1208_REG_HRA         0x0e
#define ISL1208_REG_DTA         0x0f
#define ISL1208_REG_MOA         0x10
#define ISL1208_REG_DWA         0x11
#define ISL1208_ALARM_SECTION_LEN 6
/* user section */
#define ISL1208_REG_USR1        0x12
#define ISL1208_REG_USR2        0x13
#define ISL1208_USR_SECTION_LEN 2
#define ISL1208_REGS_MAX        0x13
const char *weekday[7]={"Sun.","Mon.","Tue.","Wed.","Thu.","Fri.","Sat." };
/*
 *+----------------------------------+
 *|     ISL1208 Low level API        |
 *+----------------------------------+
 */
static int isl1208_i2c_read_regs(uint8_t regaddr, uint8_t *regs, uint8_t len)
{
    uint8_t        i;
    int            rv = 0;
    uint8_t        byte;
    uint8_t        ack;
    if( !regs || len<=0 )
    {
        rtc_print("ISL1208: Invalid input arguments\r\n");
        return -1;
    }
    I2C_StartCondition();
    if( (rv=I2C_SendAddress(I2C_WR)) < 0 )
    {
        rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
        goto OUT;
    }
    if( (rv=I2C_WriteByte(regaddr)) < 0 )
    {
        rtc_print("ISL1208: Set register[0x%02x] failure: rv=0x%02x\r\n", regaddr, rv);
        goto OUT;
    }
    I2C_StartCondition();
    if( (rv=I2C_SendAddress( I2C_RD )) < 0 )
    {
        rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
        goto OUT;
    }
    for (i=0; i<len; i++)
    {
         if( i == (len-1) )
             ack = ACK_NONE;
         else
             ack = ACK;
         if( (rv=I2C_ReadByte(&byte, ack, I2C_CLK_STRETCH_TIMEOUT)) < 0 )
         {
             rtc_print("ISL1208: Read register data failure: rv=0x%02x\r\n", rv);
             goto OUT;
         }
         regs[i] = byte;
    }
OUT:
    I2C_StopCondition();
    return rv;
}
static int isl1208_i2c_write_regs(uint8_t regaddr, uint8_t *regs, uint8_t len)
{
    uint8_t        i = 0;
    int            rv = 0;
    I2C_StartCondition();
    if( (rv=I2C_SendAddress(I2C_WR)) < 0 )
    {
        rtc_print("ISL1208: Send chipset address[W] failure: rv=0x%02x\r\n", rv);
        goto OUT;
    }
    if( (rv=I2C_WriteByte(regaddr)) < 0 )
    {
        rtc_print("ISL1208: Set register[0x%02x] failure: rv=0x%02x\r\n", regaddr, rv);
        goto OUT;
    }
    for (i=0; i<len; i++)
    {
        if( (rv=I2C_WriteByte(regs[i])) < 0 )
        {
            rtc_print("ISL1208: Write register data failure: rv=0x%02x\r\n", rv);
            goto OUT;
        }
    }
    rv = 0;
OUT:
    I2C_StopCondition();
    return rv;
}
#define bcd2bin(x)    (((x) & 0x0f) + ((x) >> 4) * 10)
#define bin2bcd(x)    ((((x) / 10) << 4) + (x) % 10)
int set_hwclock(hwclock_t tm)
{
    int                     rv;
    uint8_t                 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
    uint8_t                 sr;
    regs[ISL1208_REG_SC] = bin2bcd(tm.tm_sec);
    regs[ISL1208_REG_MN] = bin2bcd(tm.tm_min);
    regs[ISL1208_REG_HR] = bin2bcd(tm.tm_hour) | ISL1208_REG_HR_MIL;
    regs[ISL1208_REG_DT] = bin2bcd(tm.tm_mday);
    regs[ISL1208_REG_MO] = bin2bcd(tm.tm_mon);
    regs[ISL1208_REG_YR] = bin2bcd(tm.tm_year - 2000);
    //regs[ISL1208_REG_DW] = bin2bcd(tm.tm_wday & 7);
    if( i2c_lock(ISL1208_CHIPADDR) < 0 )
    {
        rtc_print("ISL1208: Lock I2C bus failure!\r\n");
        return -2;
    }
    rv = isl1208_i2c_read_regs(ISL1208_REG_SR, &sr, 1);
    if( rv < 0 )
    {
        rtc_print("ISL1208: read Status Register failure, rv=%d!\r\n", rv);
        rv = -3;
        goto OUT;
    }
    sr |= ISL1208_REG_SR_WRTC;
    rv = isl1208_i2c_write_regs(ISL1208_REG_SR, &sr, 1);
    if( rv < 0 )
    {
        rtc_print("ISL1208: Set Status Register WRTC failure, rv=%d!\r\n", rv);
        rv = -4;
        goto OUT;
    }
    rv=isl1208_i2c_write_regs(ISL1208_REG_SC, regs, ISL1208_RTC_SECTION_LEN);
    if(rv < 0 )
    {
        rtc_print("ISL1208: Set RTC section registeres failure, rv=%d!\r\n", rv);
        rv = -5;
        goto OUT;
    }
    sr &= (~ISL1208_REG_SR_WRTC);
    rv = isl1208_i2c_write_regs(ISL1208_REG_SR, &sr, 1);
    if( rv < 0 )
    {
        rtc_print("ISL1208: Clear Status Register WRTC failure, rv=%d!\r\n", rv);
        rv = -6;
        goto OUT;
    }
OUT:
    i2c_free();
    return rv;
}
int get_hwclock(hwclock_t *tm)
{
    int                                 rv = 0;
    uint8_t                             regs[REGS_RTC_SR_LEN] = { 0, };
    if( !tm )
    {
        rtc_print("ISL1208: Invalid input arugments!\r\n");
        return -1;
    }
    if( i2c_lock(ISL1208_CHIPADDR) < 0 )
    {
        rtc_print("ISL1208: Initial I2C bus failure!\r\n");
        return -2;
    }
    rv = isl1208_i2c_read_regs(ISL1208_REG_SC, regs, REGS_RTC_SR_LEN);
    if (rv < 0)
    {
        rtc_print("ISL1208: read RTC_SECTION and SR registeres failure, rv=%d!\r\n", rv);
        rv = -3;
        goto OUT;
    }
    if( regs[ISL1208_REG_SR] & ISL1208_REG_SR_RTCF )
    {
        rtc_print("ISL1208: Initialize RTC time after power failure!\r\n");
        rv = -4;
        goto OUT;
    }
    tm->tm_sec = bcd2bin(regs[ISL1208_REG_SC]);
    tm->tm_min = bcd2bin(regs[ISL1208_REG_MN]);
    {
        const uint8_t _hr = regs[ISL1208_REG_HR];
        if (_hr & ISL1208_REG_HR_MIL)  /* 24H */
        {
            tm->tm_hour = bcd2bin(_hr & 0x3f);
        }
        else  /* 12H */
        {
            tm->tm_hour = bcd2bin(_hr & 0x1f);
            if (_hr & ISL1208_REG_HR_PM)
                tm->tm_hour += 12;
        }
    }
    tm->tm_mday = bcd2bin(regs[ISL1208_REG_DT]);
    tm->tm_mon  = bcd2bin(regs[ISL1208_REG_MO]);
    tm->tm_year = bcd2bin(regs[ISL1208_REG_YR]) + 2000;
    tm->tm_wday = bcd2bin(regs[ISL1208_REG_DW]);
OUT:
    i2c_free();
    return rv;
}
int set_rtctime(char *time)
{
    hwclock_t       tm;
    if( 6 != sscanf(time, "%d-%d-%d %d:%d:%d",
                &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec))
    {
        return -1;
    }
    set_hwclock(tm);
    return 0;
}
int get_rtctime(char *buf, int size)
{
    hwclock_t       tm;
    memset(buf, 0, size);
    if( get_hwclock(&tm) < 0 )
        return -1;
    snprintf(buf, size, "%04d-%02d-%02d %02d:%02d:%02d\r\n",
        tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
    return 0;
}
void print_rtctime(void)
{
    hwclock_t       tm;
    if( get_hwclock(&tm) < 0 )
        return ;
    printf("%04d-%02d-%02d %02d:%02d:%02d\r\n",
        tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
Core/Src/board/isl1208.h
New file
@@ -0,0 +1,46 @@
/**********************************************************************
 *   Copyright: (C)2024 LingYun IoT System Studio
 *      Author: GuoWenxue<guowenxue@gmail.com>
 *
 * Description: ISL1208 RTC driver on ISKBoard
 *
 *   ChangeLog:
 *        Version    Date       Author            Description
 *        V1.0.0  2024.08.29    GuoWenxue      Release initial version
 *
 ***********************************************************************/
#ifndef __ISL1208_H_
#define __ISL1208_H_
typedef struct hwclock_s
{
    int       tm_sec;   /* [0 ~ 59/60 ]  */
    int       tm_min;   /* [0 ~ 59 ]     */
    int       tm_hour;  /* [0 ~ 23 ]     */
    int       tm_mday;  /* [1 ~ 31]      */
    int       tm_mon;   /* [1 ~ 12]      */
    int       tm_year;  /* [ 2000~2099 ] */
    int       tm_wday;  /* [0 ~ 6 ]      */
} hwclock_t;
extern const char    *weekday[7];
/* Set RTC time by struct $tm */
extern int set_hwclock(hwclock_t tm);
/* Get RTC time by struct $tm */
extern int get_hwclock(hwclock_t *tm);
/* Set RTC time by time string format: "2024-08-29 12:08:08" */
extern int set_rtctime(char *time);
/* Get RTC time by time string format: "2024-08-29 12:08:08" */
extern int get_rtctime(char *buf, int size);
/* Print RTC time by time string format: "2024-08-29 12:08:08" */
extern void print_rtctime(void);
#endif /* __ISL1208_H_ */
Core/Src/main.c
@@ -28,8 +28,7 @@
/* USER CODE BEGIN Includes */
#include "miscdev.h"
#include "sht20.h"
#include "w25q.h"
#include "hal_oled.h"
#include "isl1208.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -72,8 +71,7 @@
{
  /* USER CODE BEGIN 1 */
  int pos_x = 25;
  int pos_y = 1;
  /* USER CODE END 1 */
  /* MCU Configuration--------------------------------------------------------*/
@@ -102,7 +100,8 @@
  /* USER CODE BEGIN 2 */
  beep_start(2, 300);
  OLED_Init();
  printf("ISKBoard ISL1208 RTC example.\r\n");
  set_rtctime("2025-08-08 08:08:08");
  /* USER CODE END 2 */
@@ -110,17 +109,7 @@
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    OLED_Clear();
    OLED_ShowString(pos_x, pos_y, "ISKBoard", OLED_FONT16);
    HAL_Delay(1000);
    OLED_Clear();
    for(int i=0; i<HZK_LEN_LINGYUN; i++)
        OLED_ShowChinese(Hzk_LingYun, pos_x+i*16, pos_y, i);
    HAL_Delay(1000);
    OLED_Clear();
    OLED_DrawBMP(0,0, X_WIDTH,Y_WIDTH/2, bmp_logo);
    print_rtctime();
    HAL_Delay(1000);
    /* USER CODE END WHILE */