From 44f7660ea0459fc1b2d33e46506c0ac57f9803af Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Sat, 14 Jan 2023 01:24:56 +0300 Subject: [PATCH] add time setter and calibration to RTC --- G0:G070/RTC/README | 6 ++-- G0:G070/RTC/main.c | 2 +- G0:G070/RTC/proto.c | 80 ++++++++++++++++++++++++++++++++++++++---- G0:G070/RTC/proto.h | 2 +- G0:G070/RTC/rtc.bin | Bin 2716 -> 4308 bytes G0:G070/RTC/rtc.c | 72 +++++++++++++++++++++++++++++++++++++ G0:G070/RTC/rtc.h | 4 +++ G0:G070/RTC/strfunc.c | 55 +++++++++++++++++++---------- G0:G070/RTC/strfunc.h | 11 +++--- 9 files changed, 198 insertions(+), 34 deletions(-) diff --git a/G0:G070/RTC/README b/G0:G070/RTC/README index 351b779..c977189 100644 --- a/G0:G070/RTC/README +++ b/G0:G070/RTC/README @@ -2,9 +2,11 @@ Simplest work with RTC Proto: +C - set/print calibration ticks (-511..+512) to each 2^20 ticks +Sd - set date (YY MM DD Weekday) +St - set time (HH MM SS) t - print current Tms -T - print current Time like 'Mon Jan 1 00:05:19 2001' - +T - print current Time Button press - print current time @ usart3 diff --git a/G0:G070/RTC/main.c b/G0:G070/RTC/main.c index e680532..6c2c9da 100644 --- a/G0:G070/RTC/main.c +++ b/G0:G070/RTC/main.c @@ -65,7 +65,7 @@ int main(void){ int wasbo = 0; char *rcv = usart3_getline(&wasbo); if(wasbo) usart3_sendstr("Buffer overflow occured @ last message\n"); - if(rcv) rcv = parse_cmd(rcv); + if(rcv) rcv = (char*)parse_cmd(rcv); if(rcv) usart3_sendstr(rcv); } } diff --git a/G0:G070/RTC/proto.c b/G0:G070/RTC/proto.c index dca5aac..3365901 100644 --- a/G0:G070/RTC/proto.c +++ b/G0:G070/RTC/proto.c @@ -26,6 +26,9 @@ extern volatile uint32_t Tms; const char *helpstring = + "C - set/print calibration ticks (-511..+512) to each 2^20 ticks\n" + "Sd - set date (YY MM DD Weekday)\n" + "St - set time (HH MM SS)\n" "t - print current Tms\n" "T - print current Time\n" ; @@ -36,6 +39,7 @@ TRUE_INLINE void putch(char x){ static const char *weekdays[] = {"Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"}; static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"}; +static const char *OK = "OK\n"; static void prezero(uint8_t x){ if(x < 10){ putch('0'); putch('0' + x);} @@ -45,7 +49,7 @@ static void prezero(uint8_t x){ void print_curtime(){ rtc_t t; get_curtime(&t); - USND(weekdays[t.day - 1]); + USND(weekdays[t.weekday - 1]); putch(' '); USND(months[t.month - 1]); putch(' '); @@ -60,13 +64,75 @@ void print_curtime(){ putch('\n'); } -char *parse_cmd(char *buf){ - // "long" commands -/* switch(*buf){ - }*/ - // "short" commands - if(buf[1]) return buf; // echo wrong data +static int readNu8(const char *buf, uint8_t *arr, int maxlen){ + uint32_t D; + const char *nxt; + int N = 0; + while((nxt = getnum(buf, &D)) && nxt != buf && N < maxlen){ + buf = nxt; + if(D > 0xff){ + USND("Value too large\n"); + return N; + } + arr[N++] = (uint8_t) D&0xff; + } + return N; +} + +TRUE_INLINE const char* setdatetime(const char *buf){ + buf = omit_spaces(buf); + uint8_t array[4]; + rtc_t r; switch(*buf){ + case 'd': // set date + if(4 != readNu8(buf+1, array, 4)) + return "Format: YY MM DD Weekday (monday is 1)\n"; + r.year = array[0]; + r.month = array[1]; + r.day = array[2]; + r.weekday = array[3]; + if(!rtc_setdate(&r)) return "Wrong date format\n"; + break; + case 't': // set time + if(3 != readNu8(buf+1, array, 3)) + return "Format: HH MM SS\n"; + r.hour = array[0]; + r.minute = array[1]; + r.second = array[2]; + if(!rtc_settime(&r)) return "Wrong time format\n"; + break; + default: + return "Sd -> set date; St -> set time\n"; + } + return OK; +} + +TRUE_INLINE const char *setcal(const char *buf){ + int32_t v; + if(buf == getint(buf, &v)){ + USND("Calibration value: "); + USND(i2str(rtc_getcalib())); + putch('\n'); + return NULL; + } + if(!rtc_setcalib(v)) return "Enter value: -511..+512\n"; + return OK; +} + +const char *parse_cmd(char *buf){ + const char *x = omit_spaces(buf); + // "long" commands + switch(*x){ + case 'S': + return setdatetime(x + 1); + break; + case 'C': + return setcal(x + 1); + break; + } + // "short" commands + if(x[1]) return x; // echo wrong data + switch(*x){ case 't': USND("T="); USND(u2str(Tms)); diff --git a/G0:G070/RTC/proto.h b/G0:G070/RTC/proto.h index a39fa1f..88207a2 100644 --- a/G0:G070/RTC/proto.h +++ b/G0:G070/RTC/proto.h @@ -18,5 +18,5 @@ #pragma once -char *parse_cmd(char *buf); +const char *parse_cmd(char *buf); void print_curtime(); diff --git a/G0:G070/RTC/rtc.bin b/G0:G070/RTC/rtc.bin index 10bc3baf35a73a2a9b3e07706aef224b3562d685..0bb1fae5b3e46a2a85b69962249ed0a9df686df9 100755 GIT binary patch delta 2913 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 19; + if(r) *r = i - 10*u; + return (uint16_t)u; +} +#endif +static uint8_t div10b(uint8_t i, uint8_t *r){ // divide by 10 + uint32_t u = i; + u *= 52429; + u >>= 19; + if(r) *r = i - 10*u; + return (uint8_t)u; +} + +static uint8_t DEC2BCD(uint8_t x){ + uint8_t d, r; + d = div10b(x, &r); + return (d << 4 | r); +} + +int rtc_setdate(rtc_t *d){ + if(d->year > 99) return FALSE; + if(d->month > 12 || d->month == 0) return FALSE; + if(d->day > maxdays[d->month - 1] || d->day == 0) return FALSE; + if(d->month == 2 && d->day == 29 && (d->year & 4) != 4) return FALSE; // not leap year + if(d->weekday > 7 || d->weekday == 0) return FALSE; + RTC->ICSR |= RTC_ICSR_INIT; + WAITWHILE(!(RTC->ICSR & RTC_ICSR_INITF)); + RTC->DR = DEC2BCD(d->year) << RTC_DR_YU_Pos | d->weekday << RTC_DR_WDU_Pos | DEC2BCD(d->month) << RTC_DR_MU_Pos | DEC2BCD(d->day) << RTC_DR_DU_Pos; + RTC->ICSR &= ~RTC_ICSR_INIT; + return TRUE; +} + +int rtc_settime(rtc_t *t){ + if(t->hour > 23) return FALSE; + if(t->minute > 59) return FALSE; + if(t->second > 59) return FALSE; + RTC->ICSR |= RTC_ICSR_INIT; + WAITWHILE(!(RTC->ICSR & RTC_ICSR_INITF)); + RTC->TR = DEC2BCD(t->hour) << RTC_TR_HU_Pos | DEC2BCD(t->minute) << RTC_TR_MNU_Pos | DEC2BCD(t->second) << RTC_TR_SU_Pos; + RTC->ICSR &= ~RTC_ICSR_INIT; + return TRUE; +} + void rtc_setup(){ PWR->CR1 |= PWR_CR1_DBP; // disable RTC write protection // turn on LSE and switch RTC to it @@ -59,3 +109,25 @@ void get_curtime(rtc_t *t){ t->weekday = (r >> RTC_DR_WDU_Pos) & 0x7; t->year = BCDu(RTC_DR_YU_Pos) + 10 * BCDu(RTC_DR_YT_Pos); } + +// set calibration value +int rtc_setcalib(int calval){ + if(calval < -511 || calval > 512) return FALSE; + uint32_t calp = 0, calm = 0; + if(calval < 0) calm = -calval; + else if(calval > 0){ + calp = RTC_CALR_CALP; + calm = 512 - calval; + } + // unlock RCC + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + RTC->CALR = calp | calm; + return 1; +} + +int rtc_getcalib(){ + int calval = (RTC->CALR & RTC_CALR_CALP) ? 512 : 0; + calval -= RTC->CALR & 0x1ff; + return calval; +} diff --git a/G0:G070/RTC/rtc.h b/G0:G070/RTC/rtc.h index e5f8c8c..81f695a 100644 --- a/G0:G070/RTC/rtc.h +++ b/G0:G070/RTC/rtc.h @@ -34,3 +34,7 @@ typedef struct{ void rtc_setup(); void get_curtime(rtc_t *t); +int rtc_setdate(rtc_t *d); +int rtc_settime(rtc_t *t); +int rtc_setcalib(int calval); +int rtc_getcalib(); \ No newline at end of file diff --git a/G0:G070/RTC/strfunc.c b/G0:G070/RTC/strfunc.c index c52785e..89b898b 100644 --- a/G0:G070/RTC/strfunc.c +++ b/G0:G070/RTC/strfunc.c @@ -60,8 +60,11 @@ static char *_2str(uint32_t val, uint8_t minus){ *(--bufptr) = '0'; }else{ while(val){ - *(--bufptr) = val % 10 + '0'; - val /= 10; + uint32_t x = val / 10; + *(--bufptr) = (val - 10*x) + '0'; + val = x; + //*(--bufptr) = val % 10 + '0'; + //val /= 10; } } if(minus) *(--bufptr) = '-'; @@ -113,12 +116,12 @@ char *uhex2str(uint32_t val){ * @param buf - string * @return - pointer to first character in `buf` > ' ' */ -char *omit_spaces(const char *buf){ +const char *omit_spaces(const char *buf){ while(*buf){ if(*buf > ' ') break; ++buf; } - return (char*)buf; + return buf; } /** @@ -127,7 +130,7 @@ char *omit_spaces(const char *buf){ * @param N - number read * @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff */ -static char *getdec(const char *buf, uint32_t *N){ +static const char *getdec(const char *buf, uint32_t *N){ char *start = (char*)buf; uint32_t num = 0; while(*buf){ @@ -144,11 +147,11 @@ static char *getdec(const char *buf, uint32_t *N){ ++buf; } *N = num; - return (char*)buf; + return buf; } // read hexadecimal number (without 0x prefix!) -static char *gethex(const char *buf, uint32_t *N){ - char *start = (char*)buf; +static const char *gethex(const char *buf, uint32_t *N){ + const char *start = buf; uint32_t num = 0; while(*buf){ char c = *buf; @@ -173,11 +176,11 @@ static char *gethex(const char *buf, uint32_t *N){ ++buf; } *N = num; - return (char*)buf; + return buf; } // read octal number (without 0 prefix!) -static char *getoct(const char *buf, uint32_t *N){ - char *start = (char*)buf; +static const char *getoct(const char *buf, uint32_t *N){ + const char *start = (char*)buf; uint32_t num = 0; while(*buf){ char c = *buf; @@ -193,11 +196,11 @@ static char *getoct(const char *buf, uint32_t *N){ ++buf; } *N = num; - return (char*)buf; + return buf; } // read binary number (without b prefix!) -static char *getbin(const char *buf, uint32_t *N){ - char *start = (char*)buf; +static const char *getbin(const char *buf, uint32_t *N){ + const char *start = (char*)buf; uint32_t num = 0; while(*buf){ char c = *buf; @@ -213,7 +216,7 @@ static char *getbin(const char *buf, uint32_t *N){ ++buf; } *N = num; - return (char*)buf; + return buf; } /** @@ -223,9 +226,9 @@ static char *getbin(const char *buf, uint32_t *N){ * @return pointer to first non-number symbol in buf * (if it is == buf, there's no number or if *N==0xffffffff there was overflow) */ -char *getnum(const char *txt, uint32_t *N){ - char *nxt = NULL; - char *s = omit_spaces(txt); +const char *getnum(const char *txt, uint32_t *N){ + const char *nxt = NULL; + const char *s = omit_spaces(txt); if(*s == '0'){ // hex, oct or 0 if(s[1] == 'x' || s[1] == 'X'){ // hex nxt = gethex(s+2, N); @@ -247,6 +250,22 @@ char *getnum(const char *txt, uint32_t *N){ return nxt; } +// get signed integer +const char *getint(const char *txt, int32_t *I){ + const char *s = omit_spaces(txt); + int32_t sign = 1; + uint32_t U; + if(*s == '-'){ + sign = -1; + ++s; + } + const char *nxt = getnum(s, &U); + if(nxt == s) return txt; + if(U & 0x80000000) return txt; // overfull + *I = sign * (int32_t)U; + return nxt; +} + /* void mymemcpy(char *dest, const char *src, int len){ if(len < 1) return; diff --git a/G0:G070/RTC/strfunc.h b/G0:G070/RTC/strfunc.h index a6662d5..cdb27b5 100644 --- a/G0:G070/RTC/strfunc.h +++ b/G0:G070/RTC/strfunc.h @@ -21,9 +21,10 @@ #include void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len); -char *u2str(uint32_t val); -char *i2str(int32_t i); -char *uhex2str(uint32_t val); -char *getnum(const char *txt, uint32_t *N); -char *omit_spaces(const char *buf); +const char *u2str(uint32_t val); +const char *i2str(int32_t i); +const char *uhex2str(uint32_t val); +const char *getnum(const char *txt, uint32_t *N); +const char *omit_spaces(const char *buf); +const char *getint(const char *txt, int32_t *I); //void mymemcpy(char *dest, const char *src, int len);