#include<libopencm3/stm32/rtc.h> // real time clock utilities
/* own libraries */
#include"global.h" // board definitions
#include"usart.h" // USART utilities
#include"usb_cdcacm.h" // USB CDC ACM utilities
/* flag set in interrupts to be processed in main taks */
volatileboolbutton_flag=false;// button has been presse
/** @defgroup main_flags flag set in interrupts to be processed in main task
*@{
*/
volatileboolbutton_flag=false;/**< flag set when board user button has been pressed/released */
volatileboolrtc_internal_tick_flag=false;/**< flag set when internal RTC ticked */
/** @} */
/** user input command */
charcommand[32]={0};
/** user input command index */
uint8_tcommand_i=0;
/* default output (i.e. for printf) */
int_write(intfile,char*ptr,intlen)
{
inti;
inti;// how much data has been sent
staticcharnewline=0;// what newline has been sent
if(file==STDOUT_FILENO||file==STDERR_FILENO){
for(i=0;i<len;i++){
if(ptr[i]=='\n'){// add carrier return before line feed. this is recommended for most UART terminals
usart_putchar_nonblocking('\r');// a second line feed doesn't break the display
cdcacm_putchar('\r');// a second line feed doesn't break the display
if(ptr[i]=='\r'||ptr[i]=='\n'){// send CR+LF newline for most carriage return and line feed combination
if(newline==0||(newline==ptr[i])){// newline has already been detected
usart_putchar_nonblocking('\r');// send newline over USART
usart_putchar_nonblocking('\n');// send newline over USART
cdcacm_putchar('\r');// send newline over USB
cdcacm_putchar('\n');// send newline over USB
newline=ptr[i];// remember the newline
}
if(ptr[i]=='\n'){// line feed are always considered to end a line (the LF+CR combination is not supported to better support the others)
newline=0;// clear new line
}
}else{// non-newline character
usart_putchar_nonblocking(ptr[i]);// send byte over USART
cdcacm_putchar(ptr[i]);// send byte over USB
newline=0;// clear new line
}
usart_putchar_nonblocking(ptr[i]);// send byte over USART
cdcacm_putchar(ptr[i]);// send byte over USB
}
returni;
}
@ -57,82 +83,178 @@ int _write(int file, char *ptr, int len)
return-1;
}
/* switch on LED */
voidled_on(void)
char*b2s(uint64_tbinary,uint8_trjust)
{
#ifdef SYSTEM_BOARD
gpio_clear(LED_PORT,LED_PIN);
#elif MAPLE_MINI
gpio_set(LED_PORT,LED_PIN);
#endif
}
staticcharstring[64+1]={0};// the string representation to return
int8_tbit=LENGTH(string)-1;// the index of the bit to print
string[bit--]=0;// terminate string
/* switch off LED */
voidled_off(void)
{
#ifdef SYSTEM_BOARD
gpio_set(LED_PORT,LED_PIN);
#elif MAPLE_MINI
gpio_clear(LED_PORT,LED_PIN);
#endif
while(binary){
if(binary&1){
string[bit--]='1';
}else{
string[bit--]='0';
}
binary>>=1;
}
while(64-bit-1<rjust&&bit>=0){
string[bit--]='0';
}
return&string[bit+1];
}
/* toggle LED */
voidled_toggle(void)
/** process user command
*@param[in]strusercommandstring(\0ended)
*/
staticvoidprocess_command(char*str)
{
gpio_toggle(LED_PORT,LED_PIN);
// split command
constchar*delimiter="";
char*word=strtok(str,delimiter);
if(!word){
gotoerror;
}
// parse command
if(0==strcmp(word,"help")){
printf("available commands:\n");
printf("led [on|off|toggle]\n");
printf("time [HH:MM:SS]\n");
}elseif(0==strcmp(word,"led")){
word=strtok(NULL,delimiter);
if(!word){
gotoerror;
}elseif(0==strcmp(word,"on")){
led_on();// switch LED on
printf("LED switched on\n");// notify user
}elseif(0==strcmp(word,"off")){
led_off();// switch LED off
printf("LED switched off\n");// notify user
}elseif(0==strcmp(word,"toggle")){
led_toggle();// toggle LED
printf("LED toggled\n");// notify user
}else{
gotoerror;
}
}elseif(0==strcmp(word,"time")){
word=strtok(NULL,delimiter);
if(!word){
printf("current time: %02lu:%02lu:%02lu\n",rtc_get_counter_val()/(60*60),(rtc_get_counter_val()%(60*60))/60,(rtc_get_counter_val()%60));// get and print time from internal RTC
}elseif(strlen(word)!=8||word[0]<'0'||word[0]>'2'||word[1]<'0'||word[1]>'9'||word[3]<'0'||word[3]>'5'||word[4]<'0'||word[4]>'9'||word[6]<'0'||word[6]>'5'||word[7]<'0'||word[7]>'9'){// time format is incorrect
gotoerror;
}else{
rtc_set_counter_val(((word[0]-'0')*10+(word[1]-'0')*1)*(60*60)+((word[3]-'0')*10+(word[4]-'0')*1)*60+((word[6]-'0')*10+(word[7]-'0')*1));// set time in internal RTC counter
printf("time set\n");
}
}else{
gotoerror;
}
return;// command successfully processed
error:
printf("command not recognized. enter help to list commands\n");
printf("welcome to the STM32F1 CuVoodoo example code\n");// print welcome message
led_on();// switch on LED to indicate setup completed
// setup RTC
printf("setup internal RTC: ");
rtc_auto_awake(RCC_LSE,32768-1);// ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect)
rtc_interrupt_enable(RTC_SEC);// enable RTC interrupt on "seconds"
nvic_enable_irq(NVIC_RTC_IRQ);// allow the RTC to interrupt
printf("OK\n");
// get date and time
uint32_tticks_time=0;
ticks_time=rtc_get_counter_val();// get time/date from internal RTC
printf("current time: %02lu:%02lu:%02lu\n",ticks_time/(60*60),(ticks_time%(60*60))/60,(ticks_time%60));// display time
// main loop
printf("command input: ready\n");
boolaction=false;// if an action has been performed don't go to sleep
button_flag=false;// reset button flag
/* toggle the LED with every transmitted character */
charc='';// to store received character
boolchar_flag=false;// a new character has been received
while(true){// infinite loop
while(usart_received){// echo every received character
while(usart_received){// data received over UART
action=true;// action has been performed
led_toggle();// toggle LED
printf("%c",usart_getchar());// transmit receive character
c=usart_getchar();// store receive character
char_flag=true;// notify character has been received
}
while(cdcacm_received){// echo every received character
while(cdcacm_received){// data received over USB
action=true;// action has been performed
led_toggle();// toggle LED
printf("%c",cdcacm_getchar());// transmit receive character
c=cdcacm_getchar();// store receive character
char_flag=true;// notify character has been received
}
while(button_flag){
button_flag=false;// reset flag
while(char_flag){// user data received
char_flag=false;// reset flag
action=true;// action has been performed
printf("%c",c);// echo receive character
if(c=='\r'||c=='\n'){// end of command received
if(command_i>0){// there is a command to process
command[command_i]=0;// end string
command_i=0;// prepare for next command
process_command(command);// process user command
}
}else{// user command input
command[command_i]=c;// save command input
if(command_i<LENGTH(command)-2){// verify if there is place to save next character
command_i++;// save next character
}
}
}
while(button_flag){// user pressed button
action=true;// action has been performed
printf("button pressed\n");
led_toggle();// toggle LED
for(uint32_ti=0;i<1000000;i++){// wait a bit to remove noise and double trigger
__asm__("nop");
}
button_flag=false;// reset flag
}
// go to sleep if nothing had to be done, else recheck for activity
if(action){
while(rtc_internal_tick_flag){// the internal RTC ticked
rtc_internal_tick_flag=false;// reset flag
ticks_time=rtc_get_counter_val();// copy time from internal RTC for processing
action=true;// action has been performed
if((ticks_time%(60*60))==0){// one minute passed
printf("%02lu:%02lu:%02lu\n",ticks_time/(60*60),(ticks_time%(60*60))/60,(ticks_time%60));// display external time
}
}
if(action){// go to sleep if nothing had to be done, else recheck for activity
action=false;
}else{
__WFI();// go to sleep
@ -143,9 +265,17 @@ int main(void)
}
#if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
/** interrupt service routine called when button is pressed */