Solution how to fix broken RTC on Nucleo_F103RB / STM32F103 BluePill etc..

Dependencies:   mbed-dev

Fork of Nucleo_RTC_battery_bkup_pwr_off_okay by Kenji Arai

Experimental fork https://os.mbed.com/users/kenjiArai/code/Nucleo_RTC_battery_bkup_pwr_off_okay/ to fix broken RTC on Nucleo_F103RB / STM32F103 BluePill etc..

At this moment (7/11/17) use forked mbed-dev https://os.mbed.com/users/maxxir/code/mbed-dev/.

Or require patch for ./mbed-dev/targets/TARGET_STM/rtc_api.c.

You can manual add to your project fresh mbed-dev and change file mbed-dev\targets\TARGET_STM\rtc_api.c from root project patched rtc_api.c.stm32f10x.txt.

Exploring origin errors, I saw that something wrong with HAL API on STM32F1xx with this functions:

 HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);

 HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);


 HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);

 HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);

Look here (as I understand it possible broken on STM32CUBE HAL level now):

https://community.st.com/thread/43218-stm32f103-loss-rtc-date-when-reset

So I use direct RTC register manipulation for STM32F1xx:

rtc_read(), rtc_write() (native rtc_init() - works good).

Also added stub for non-working on STM32F1xx rtc_read_subseconds().

Now the stm32F103 can survive power off, and allows you to get and set the time.

Tested OK on boards:

NUCLEO STM32F103RB, DIY STM32F100CB (forked from DISCO_F100RB)

Happy coding!

maxxir

10/11/17

Committer:
kenjiArai
Date:
Mon Jan 16 09:38:03 2017 +0000
Revision:
9:6a64b0207f72
Parent:
8:bf593344668e
Child:
10:0c6dfc996c1a
mbed supports RTC function during RESET & Power ON/OFF. You don't need any modification for mbed library source code. You can just check RTC!!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:0751c92c0f71 1 /*
kenjiArai 0:0751c92c0f71 2 * mbed Application program
kenjiArai 0:0751c92c0f71 3 * RTC (inside STM32x CPU) test program
kenjiArai 0:0751c92c0f71 4 *
kenjiArai 9:6a64b0207f72 5 * Copyright (c) 2015,'16,'17 Kenji Arai / JH1PJL
kenjiArai 0:0751c92c0f71 6 * http://www.page.sannet.ne.jp/kenjia/index.html
kenjiArai 0:0751c92c0f71 7 * http://mbed.org/users/kenjiArai/
kenjiArai 0:0751c92c0f71 8 * Created: January 17th, 2015
kenjiArai 9:6a64b0207f72 9 * Revised: January 16th, 2017
kenjiArai 0:0751c92c0f71 10 *
kenjiArai 9:6a64b0207f72 11 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
kenjiArai 9:6a64b0207f72 12 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
kenjiArai 9:6a64b0207f72 13 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
kenjiArai 9:6a64b0207f72 14 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
kenjiArai 9:6a64b0207f72 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
kenjiArai 9:6a64b0207f72 16 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
kenjiArai 9:6a64b0207f72 17 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
kenjiArai 9:6a64b0207f72 18 */
kenjiArai 9:6a64b0207f72 19
kenjiArai 9:6a64b0207f72 20 /* mbed library now suports RTC continuous operation at Reset & Power ON/OFF
kenjiArai 9:6a64b0207f72 21 --------------------------------------------------------------------------
kenjiArai 9:6a64b0207f72 22 In the past, rtc_api.c (inside mbed) alway made a reset RTC registers
kenjiArai 9:6a64b0207f72 23 when user push a reset buttom or terninate a power.
kenjiArai 9:6a64b0207f72 24 Even if user configures a back-up circuit for RTC, mbed board could not
kenjiArai 9:6a64b0207f72 25 keep proper time.
kenjiArai 9:6a64b0207f72 26 I have checked mbed rev.133 and mbed-dev rev.155.
kenjiArai 0:0751c92c0f71 27 */
kenjiArai 0:0751c92c0f71 28
kenjiArai 9:6a64b0207f72 29 /*
kenjiArai 9:6a64b0207f72 30 ----- Tested board -----
kenjiArai 9:6a64b0207f72 31 / Reset: / Stanby: / power off and restart:
kenjiArai 9:6a64b0207f72 32 Nucleo-F401RE / ok / ok / ok (need following Back-up Circuit)
kenjiArai 9:6a64b0207f72 33 Nucleo-F411RE / ok / ok / ok (need following Back-up Circuit)
kenjiArai 9:6a64b0207f72 34 Nucleo-F446RE / ok / ok / ok (need following Back-up Circuit)
kenjiArai 9:6a64b0207f72 35 Nucleo-F334R8 / ok / ok / ok (need following Back-up Circuit)
kenjiArai 9:6a64b0207f72 36 Nucleo-L476RG / ok / ok / ok (need following Back-up Circuit)
kenjiArai 9:6a64b0207f72 37 Nucleo-L152RE / ok / ok / no check (Need additional hardware)
kenjiArai 9:6a64b0207f72 38 Nucleo-L073RZ / ok / ok / no check (Need additional hardware)
kenjiArai 9:6a64b0207f72 39 Nucleo-L053R8 / ok / ok / no check (Need additional hardware)
kenjiArai 0:0751c92c0f71 40
kenjiArai 9:6a64b0207f72 41 < Back-up circuit >
kenjiArai 9:6a64b0207f72 42 CN7 VIN <- SBD <- 330 Ohm <- CR2032 + - -> CN7 GND
kenjiArai 9:6a64b0207f72 43 Remove SB45 Zero Ohm resistor
kenjiArai 9:6a64b0207f72 44 */
kenjiArai 8:bf593344668e 45
kenjiArai 9:6a64b0207f72 46 // Include --------------------------------------------------------------------
kenjiArai 9:6a64b0207f72 47 #include "mbed.h"
kenjiArai 9:6a64b0207f72 48
kenjiArai 9:6a64b0207f72 49 // Definition -----------------------------------------------------------------
kenjiArai 8:bf593344668e 50 #if (defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG))
kenjiArai 8:bf593344668e 51 #define PUSHED_SW 1 // Active high
kenjiArai 8:bf593344668e 52 #else
kenjiArai 8:bf593344668e 53 #define PUSHED_SW 0 // Active low
kenjiArai 1:7a48c475bbd2 54 #endif
kenjiArai 1:7a48c475bbd2 55
kenjiArai 9:6a64b0207f72 56 // Object ---------------------------------------------------------------------
kenjiArai 0:0751c92c0f71 57 DigitalIn userSW(USER_BUTTON);
kenjiArai 0:0751c92c0f71 58 DigitalOut myled(LED1); // Indicate the sampling period
kenjiArai 0:0751c92c0f71 59 Serial pc(USBTX, USBRX);
kenjiArai 0:0751c92c0f71 60
kenjiArai 9:6a64b0207f72 61 // RAM ------------------------------------------------------------------------
kenjiArai 0:0751c92c0f71 62
kenjiArai 9:6a64b0207f72 63 // ROM / Constant data --------------------------------------------------------
kenjiArai 8:bf593344668e 64 char *const msg0 = "Is a time correct? If no, please hit any key. ";
kenjiArai 8:bf593344668e 65 char *const msg1 = "<Push USER SW then enter sleep mode> ";
kenjiArai 8:bf593344668e 66 char *const msg2 = "\r\nEnter Standby Mode, please push RESET to wake-up\r\n";
kenjiArai 0:0751c92c0f71 67
kenjiArai 9:6a64b0207f72 68 // Function prototypes --------------------------------------------------------
kenjiArai 9:6a64b0207f72 69 static void time_enter_mode(void);
kenjiArai 9:6a64b0207f72 70 static void chk_and_set_time(char *ptr);
kenjiArai 9:6a64b0207f72 71 static void goto_standby(void);
kenjiArai 9:6a64b0207f72 72 static int xatoi (char **str, unsigned long *res);
kenjiArai 9:6a64b0207f72 73 static void get_line (char *buff, int len);
kenjiArai 9:6a64b0207f72 74
kenjiArai 9:6a64b0207f72 75 //------------------------------------------------------------------------------
kenjiArai 0:0751c92c0f71 76 // Control Program
kenjiArai 9:6a64b0207f72 77 //------------------------------------------------------------------------------
kenjiArai 0:0751c92c0f71 78 int main()
kenjiArai 0:0751c92c0f71 79 {
kenjiArai 8:bf593344668e 80 char buf[64]; // data buffer for text
kenjiArai 0:0751c92c0f71 81 time_t seconds;
kenjiArai 4:a9cebfe4715f 82 uint8_t wait_counter = 0;
kenjiArai 0:0751c92c0f71 83
kenjiArai 6:5ada291037aa 84 wait(2.0);
kenjiArai 0:0751c92c0f71 85 pc.printf("\r\n\r\nTest Nucleo RTC Function\r\n");
kenjiArai 2:77ec44bf1fa5 86 myled = !myled;
kenjiArai 0:0751c92c0f71 87 // waiting for Initial screen
kenjiArai 0:0751c92c0f71 88 myled = 1;
kenjiArai 0:0751c92c0f71 89 wait(1.0);
kenjiArai 0:0751c92c0f71 90 myled = !myled;
kenjiArai 0:0751c92c0f71 91 wait(1.0);
kenjiArai 0:0751c92c0f71 92 while(1) {
kenjiArai 0:0751c92c0f71 93 seconds = time(NULL);
kenjiArai 8:bf593344668e 94 strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
kenjiArai 9:6a64b0207f72 95 pc.printf("[Time] %s", buf);
kenjiArai 8:bf593344668e 96 pc.printf(msg0);
kenjiArai 8:bf593344668e 97 pc.printf("%s\r", msg1);
kenjiArai 4:a9cebfe4715f 98 wait_counter = 0;
kenjiArai 2:77ec44bf1fa5 99 while (seconds == time(NULL)){
kenjiArai 0:0751c92c0f71 100 if (pc.readable() == 1){
kenjiArai 0:0751c92c0f71 101 buf[0] = pc.getc(); // dummy read
kenjiArai 0:0751c92c0f71 102 time_enter_mode();
kenjiArai 0:0751c92c0f71 103 }
kenjiArai 8:bf593344668e 104 if (userSW == PUSHED_SW){
kenjiArai 8:bf593344668e 105 pc.printf(msg2);
kenjiArai 2:77ec44bf1fa5 106 wait(1.0);
kenjiArai 2:77ec44bf1fa5 107 myled = 0;
kenjiArai 3:7b3edf54c706 108 goto_standby();
kenjiArai 2:77ec44bf1fa5 109 }
kenjiArai 4:a9cebfe4715f 110 wait(0.05);
kenjiArai 4:a9cebfe4715f 111 if (++wait_counter > (2000 / 50)){
kenjiArai 4:a9cebfe4715f 112 break;
kenjiArai 4:a9cebfe4715f 113 }
kenjiArai 0:0751c92c0f71 114 }
kenjiArai 8:bf593344668e 115 uint8_t n = strlen(msg0) + strlen(msg1);
kenjiArai 8:bf593344668e 116 for (uint8_t i = 0; i < n; i++){
kenjiArai 8:bf593344668e 117 pc.putc(' ');
kenjiArai 2:77ec44bf1fa5 118 }
kenjiArai 8:bf593344668e 119 pc.printf(" \r"); // Not use '\n'
kenjiArai 2:77ec44bf1fa5 120 myled = !myled;
kenjiArai 0:0751c92c0f71 121 }
kenjiArai 0:0751c92c0f71 122 }
kenjiArai 9:6a64b0207f72 123
kenjiArai 9:6a64b0207f72 124 void time_enter_mode(void)
kenjiArai 9:6a64b0207f72 125 {
kenjiArai 9:6a64b0207f72 126 char *ptr;
kenjiArai 9:6a64b0207f72 127 char linebuf[64];
kenjiArai 9:6a64b0207f72 128
kenjiArai 9:6a64b0207f72 129 pc.printf("\r\nSet time into RTC\r\n");
kenjiArai 9:6a64b0207f72 130 pc.printf(" e.g. >17 1 16 20 55 23 -> January 16th,'17, 20:55:23\r\n");
kenjiArai 9:6a64b0207f72 131 pc.printf(" If time is fine, just hit enter\r\n");
kenjiArai 9:6a64b0207f72 132 pc.putc('>');
kenjiArai 9:6a64b0207f72 133 ptr = linebuf;
kenjiArai 9:6a64b0207f72 134 get_line(ptr, sizeof(linebuf));
kenjiArai 9:6a64b0207f72 135 pc.printf("\r");
kenjiArai 9:6a64b0207f72 136 chk_and_set_time(ptr);
kenjiArai 9:6a64b0207f72 137 }
kenjiArai 9:6a64b0207f72 138
kenjiArai 9:6a64b0207f72 139 void goto_standby(void)
kenjiArai 9:6a64b0207f72 140 {
kenjiArai 9:6a64b0207f72 141 deepsleep(); // Not Standby Mode but Deep Sleep Mode
kenjiArai 9:6a64b0207f72 142 }
kenjiArai 9:6a64b0207f72 143
kenjiArai 9:6a64b0207f72 144 // Change string -> integer
kenjiArai 9:6a64b0207f72 145 int xatoi (char **str, unsigned long *res)
kenjiArai 9:6a64b0207f72 146 {
kenjiArai 9:6a64b0207f72 147 unsigned long val;
kenjiArai 9:6a64b0207f72 148 unsigned char c, radix, s = 0;
kenjiArai 9:6a64b0207f72 149
kenjiArai 9:6a64b0207f72 150 while ((c = **str) == ' ') (*str)++;
kenjiArai 9:6a64b0207f72 151 if (c == '-') {
kenjiArai 9:6a64b0207f72 152 s = 1;
kenjiArai 9:6a64b0207f72 153 c = *(++(*str));
kenjiArai 9:6a64b0207f72 154 }
kenjiArai 9:6a64b0207f72 155 if (c == '0') {
kenjiArai 9:6a64b0207f72 156 c = *(++(*str));
kenjiArai 9:6a64b0207f72 157 if (c <= ' ') {
kenjiArai 9:6a64b0207f72 158 *res = 0;
kenjiArai 9:6a64b0207f72 159 return 1;
kenjiArai 9:6a64b0207f72 160 }
kenjiArai 9:6a64b0207f72 161 if (c == 'x') {
kenjiArai 9:6a64b0207f72 162 radix = 16;
kenjiArai 9:6a64b0207f72 163 c = *(++(*str));
kenjiArai 9:6a64b0207f72 164 } else {
kenjiArai 9:6a64b0207f72 165 if (c == 'b') {
kenjiArai 9:6a64b0207f72 166 radix = 2;
kenjiArai 9:6a64b0207f72 167 c = *(++(*str));
kenjiArai 9:6a64b0207f72 168 } else {
kenjiArai 9:6a64b0207f72 169 if ((c >= '0')&&(c <= '9')) {
kenjiArai 9:6a64b0207f72 170 radix = 8;
kenjiArai 9:6a64b0207f72 171 } else {
kenjiArai 9:6a64b0207f72 172 return 0;
kenjiArai 9:6a64b0207f72 173 }
kenjiArai 9:6a64b0207f72 174 }
kenjiArai 9:6a64b0207f72 175 }
kenjiArai 9:6a64b0207f72 176 } else {
kenjiArai 9:6a64b0207f72 177 if ((c < '1')||(c > '9')) {
kenjiArai 9:6a64b0207f72 178 return 0;
kenjiArai 9:6a64b0207f72 179 }
kenjiArai 9:6a64b0207f72 180 radix = 10;
kenjiArai 9:6a64b0207f72 181 }
kenjiArai 9:6a64b0207f72 182 val = 0;
kenjiArai 9:6a64b0207f72 183 while (c > ' ') {
kenjiArai 9:6a64b0207f72 184 if (c >= 'a') c -= 0x20;
kenjiArai 9:6a64b0207f72 185 c -= '0';
kenjiArai 9:6a64b0207f72 186 if (c >= 17) {
kenjiArai 9:6a64b0207f72 187 c -= 7;
kenjiArai 9:6a64b0207f72 188 if (c <= 9) return 0;
kenjiArai 9:6a64b0207f72 189 }
kenjiArai 9:6a64b0207f72 190 if (c >= radix) return 0;
kenjiArai 9:6a64b0207f72 191 val = val * radix + c;
kenjiArai 9:6a64b0207f72 192 c = *(++(*str));
kenjiArai 9:6a64b0207f72 193 }
kenjiArai 9:6a64b0207f72 194 if (s) val = -val;
kenjiArai 9:6a64b0207f72 195 *res = val;
kenjiArai 9:6a64b0207f72 196 return 1;
kenjiArai 9:6a64b0207f72 197 }
kenjiArai 9:6a64b0207f72 198
kenjiArai 9:6a64b0207f72 199 // Get key input data
kenjiArai 9:6a64b0207f72 200 void get_line (char *buff, int len)
kenjiArai 9:6a64b0207f72 201 {
kenjiArai 9:6a64b0207f72 202 char c;
kenjiArai 9:6a64b0207f72 203 int idx = 0;
kenjiArai 9:6a64b0207f72 204
kenjiArai 9:6a64b0207f72 205 for (;;) {
kenjiArai 9:6a64b0207f72 206 c = pc.getc();
kenjiArai 9:6a64b0207f72 207 if (c == '\r') {
kenjiArai 9:6a64b0207f72 208 buff[idx++] = c;
kenjiArai 9:6a64b0207f72 209 break;
kenjiArai 9:6a64b0207f72 210 }
kenjiArai 9:6a64b0207f72 211 if ((c == '\b') && idx) {
kenjiArai 9:6a64b0207f72 212 idx--;
kenjiArai 9:6a64b0207f72 213 pc.putc(c);
kenjiArai 9:6a64b0207f72 214 pc.putc(' ');
kenjiArai 9:6a64b0207f72 215 pc.putc(c);
kenjiArai 9:6a64b0207f72 216 }
kenjiArai 9:6a64b0207f72 217 if (((uint8_t)c >= ' ') && (idx < len - 1)) {
kenjiArai 9:6a64b0207f72 218 buff[idx++] = c;
kenjiArai 9:6a64b0207f72 219 pc.putc(c);
kenjiArai 9:6a64b0207f72 220 }
kenjiArai 9:6a64b0207f72 221 }
kenjiArai 9:6a64b0207f72 222 buff[idx] = 0;
kenjiArai 9:6a64b0207f72 223 pc.putc('\n');
kenjiArai 9:6a64b0207f72 224 }
kenjiArai 9:6a64b0207f72 225
kenjiArai 9:6a64b0207f72 226 void chk_and_set_time(char *ptr)
kenjiArai 9:6a64b0207f72 227 {
kenjiArai 9:6a64b0207f72 228 unsigned long p1;
kenjiArai 9:6a64b0207f72 229 struct tm t;
kenjiArai 9:6a64b0207f72 230 time_t seconds;
kenjiArai 9:6a64b0207f72 231
kenjiArai 9:6a64b0207f72 232 if (xatoi(&ptr, &p1)) {
kenjiArai 9:6a64b0207f72 233 t.tm_year = (uint8_t)p1 + 100;
kenjiArai 9:6a64b0207f72 234 pc.printf("Year:%d ",p1);
kenjiArai 9:6a64b0207f72 235 xatoi( &ptr, &p1 );
kenjiArai 9:6a64b0207f72 236 t.tm_mon = (uint8_t)p1 - 1;
kenjiArai 9:6a64b0207f72 237 pc.printf("Month:%d ",p1);
kenjiArai 9:6a64b0207f72 238 xatoi( &ptr, &p1 );
kenjiArai 9:6a64b0207f72 239 t.tm_mday = (uint8_t)p1;
kenjiArai 9:6a64b0207f72 240 pc.printf("Day:%d ",p1);
kenjiArai 9:6a64b0207f72 241 xatoi( &ptr, &p1 );
kenjiArai 9:6a64b0207f72 242 t.tm_hour = (uint8_t)p1;
kenjiArai 9:6a64b0207f72 243 pc.printf("Hour:%d ",p1);
kenjiArai 9:6a64b0207f72 244 xatoi( &ptr, &p1 );
kenjiArai 9:6a64b0207f72 245 t.tm_min = (uint8_t)p1;
kenjiArai 9:6a64b0207f72 246 pc.printf("Min:%d ",p1);
kenjiArai 9:6a64b0207f72 247 xatoi( &ptr, &p1 );
kenjiArai 9:6a64b0207f72 248 t.tm_sec = (uint8_t)p1;
kenjiArai 9:6a64b0207f72 249 pc.printf("Sec: %d \r\n",p1);
kenjiArai 9:6a64b0207f72 250 } else {
kenjiArai 9:6a64b0207f72 251 return;
kenjiArai 9:6a64b0207f72 252 }
kenjiArai 9:6a64b0207f72 253 seconds = mktime(&t);
kenjiArai 9:6a64b0207f72 254 set_time(seconds);
kenjiArai 9:6a64b0207f72 255 // Show Time with several example
kenjiArai 9:6a64b0207f72 256 // ex.1
kenjiArai 9:6a64b0207f72 257 pc.printf(
kenjiArai 9:6a64b0207f72 258 "Date: %04d/%02d/%02d, %02d:%02d:%02d\r\n",
kenjiArai 9:6a64b0207f72 259 t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec
kenjiArai 9:6a64b0207f72 260 );
kenjiArai 9:6a64b0207f72 261 #if 0
kenjiArai 9:6a64b0207f72 262 time_t seconds;
kenjiArai 9:6a64b0207f72 263 char buf[40];
kenjiArai 9:6a64b0207f72 264
kenjiArai 9:6a64b0207f72 265 seconds = mktime(&t);
kenjiArai 9:6a64b0207f72 266 // ex.2
kenjiArai 9:6a64b0207f72 267 strftime(buf, 40, "%x %X", localtime(&seconds));
kenjiArai 9:6a64b0207f72 268 pc.printf("Date: %s\r\n", buf);
kenjiArai 9:6a64b0207f72 269 // ex.3
kenjiArai 9:6a64b0207f72 270 strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds));
kenjiArai 9:6a64b0207f72 271 pc.printf("Date: %s\r\n", buf);
kenjiArai 9:6a64b0207f72 272 // ex.4
kenjiArai 9:6a64b0207f72 273 strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
kenjiArai 9:6a64b0207f72 274 pc.printf("Date: %s\r\n", buf);
kenjiArai 9:6a64b0207f72 275 #endif
kenjiArai 9:6a64b0207f72 276 }