rcc_periph_clock_enable(RCC_TIM(UART_SOFT_RX_TIMER));// enable clock for timer peripheral
timer_reset(TIM(UART_SOFT_RX_TIMER));// reset timer state
timer_set_mode(TIM(UART_SOFT_RX_TIMER),TIM_CR1_CKD_CK_INT,TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);// set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(UART_SOFT_RX_TIMER),0);// prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq(NVIC_TIM_IRQ(UART_SOFT_RX_TIMER));// allow interrupt for timer
timer_enable_counter(TIM(UART_SOFT_RX_TIMER));// start timer to generate interrupts for the receive pins
#endif
#if defined(UART_SOFT_TX_TIMER)
rcc_periph_clock_enable(RCC_TIM(UART_SOFT_TX_TIMER));// enable clock for timer peripheral
timer_reset(TIM(UART_SOFT_TX_TIMER));// reset timer state
timer_set_mode(TIM(UART_SOFT_TX_TIMER),TIM_CR1_CKD_CK_INT,TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);// set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(UART_SOFT_TX_TIMER),0);// prescaler to be able to output 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq(NVIC_TIM_IRQ(UART_SOFT_TX_TIMER));// allow interrupt for timer
timer_enable_counter(TIM(UART_SOFT_TX_TIMER));// start timer to generate interrupts for the transmit pins
if(uart_soft_rx_states[uart]->buffer_byte_used){// temporary byte has been stored
uart_soft_rx_states[uart]->buffer[(uart_soft_rx_states[uart]->buffer_i+uart_soft_rx_states[uart]->buffer_used)%LENGTH(uart_soft_rx_states[uart]->buffer)]=uart_soft_rx_states[uart]->buffer_byte;// put byte in buffer
uart_soft_rx_states[uart]->buffer_used++;// update used buffer
uart_soft_rx_states[uart]->buffer_byte_used=false;// buffer byte is now in buffer
}
uart_soft_received[uart]=(uart_soft_rx_states[uart]->buffer_used!=0);// notify user if data is available
if(timer_interrupt_source(TIM(UART_SOFT_RX_TIMER),timer_flags[rx])){// got a match on compare for receive pin
timer_clear_flag(TIM(UART_SOFT_RX_TIMER),timer_flags[rx]);// clear flag
if(!uart_soft_rx_states[rx]){// verify if RX exists
continue;// skip if receive port is not defined it
}
uart_soft_rx_states[rx]->byte+=((gpio_get(uart_soft_rx_states[rx]->port,uart_soft_rx_states[rx]->pin)==0?0:1)<<(uart_soft_rx_states[rx]->bit-1));// save bit value
if(uart_soft_rx_states[rx]->bit<8){// not the last bit received
timer_set_oc_value(TIM(UART_SOFT_RX_TIMER),timer_oc[rx],timer_get_counter(TIM(UART_SOFT_RX_TIMER))+rcc_ahb_frequency/uart_soft_rx_states[rx]->baudrate);// set timer to next bit
uart_soft_rx_states[rx]->bit++;// wait for next bit
}else{// last bit received
if(uart_soft_rx_states[rx]->lock){// someone is already reading data
uart_soft_rx_states[rx]->buffer_byte=uart_soft_rx_states[rx]->byte;// save byte
uart_soft_rx_states[rx]->buffer_byte_used=true;// notify reader there is a temporary byte
}else{// buffer can be updated
if(uart_soft_rx_states[rx]->buffer_used>=LENGTH(uart_soft_rx_states[rx]->buffer)){// buffer is full
uart_soft_rx_states[rx]->buffer_i=(uart_soft_rx_states[rx]->buffer_i+1)%LENGTH(uart_soft_rx_states[rx]->buffer);// drop oldest byte
uart_soft_rx_states[rx]->buffer[(uart_soft_rx_states[rx]->buffer_i+uart_soft_rx_states[rx]->buffer_used)%LENGTH(uart_soft_rx_states[rx]->buffer)]=uart_soft_rx_states[rx]->byte;// put byte in buffer
uart_soft_rx_states[rx]->buffer_used++;// update used buffer
uart_soft_received[rx]=true;// notify user data is available
gpio_clear(uart_soft_tx_states[uart]->port,uart_soft_tx_states[uart]->pin);// output start bit
timer_set_oc_value(TIM(UART_SOFT_TX_TIMER),timer_oc[uart],timer_get_counter(TIM(UART_SOFT_TX_TIMER))+(rcc_ahb_frequency/uart_soft_tx_states[uart]->baudrate));// set timer to output UART frame 1 (data bit 0) in 1 bit
timer_clear_flag(TIM(UART_SOFT_TX_TIMER),timer_flags[uart]);// clear flag before enabling interrupt
timer_enable_irq(TIM(UART_SOFT_TX_TIMER),timer_interrupt[uart]);// enable timer IRQ for TX for this UART
if(uart>=4||!uart_soft_tx_states[uart]){// ensure transmit UART port is defined
return;// return
}
while(uart_soft_tx_states[uart]->buffer_used>=LENGTH(uart_soft_tx_states[uart]->buffer)){// idle until there is place in the buffer
__WFI();// sleep until something happened
}
uart_soft_tx_states[uart]->buffer[(uart_soft_tx_states[uart]->buffer_i+uart_soft_tx_states[uart]->buffer_used)%LENGTH(uart_soft_tx_states[uart]->buffer)]=byte;// save byte to be transmitted
uart_soft_tx_states[uart]->buffer_used++;// update used buffer
if(timer_interrupt_source(TIM(UART_SOFT_TX_TIMER),timer_flags[tx])){// got a match on compare for transmit pin
timer_clear_flag(TIM(UART_SOFT_TX_TIMER),timer_flags[tx]);// clear flag
if(!uart_soft_tx_states[tx]){// verify if transmit is defined
continue;// skip if transmit port is not defined it
}
if(uart_soft_tx_states[tx]->bit<8){// there is a data bit to transmit
if((uart_soft_tx_states[tx]->byte>>uart_soft_tx_states[tx]->bit)&0x01){// bit to transmit is a 1
gpio_set(uart_soft_tx_states[tx]->port,uart_soft_tx_states[tx]->pin);// set output to high
}else{// bit to transmit is a 0
gpio_clear(uart_soft_tx_states[tx]->port,uart_soft_tx_states[tx]->pin);// set output to low
}
timer_set_oc_value(TIM(UART_SOFT_TX_TIMER),timer_oc[tx],timer_get_counter(TIM(UART_SOFT_TX_TIMER))+(rcc_ahb_frequency/uart_soft_tx_states[tx]->baudrate));// wait for the next frame bit
uart_soft_tx_states[tx]->bit++;// go to next bit
}elseif(uart_soft_tx_states[tx]->bit==8){// transmit stop bit
gpio_set(uart_soft_tx_states[tx]->port,uart_soft_tx_states[tx]->pin);// go idle high
timer_set_oc_value(TIM(UART_SOFT_TX_TIMER),timer_oc[tx],timer_get_counter(TIM(UART_SOFT_TX_TIMER))+(rcc_ahb_frequency/uart_soft_tx_states[tx]->baudrate));// wait for 1 stop bit
uart_soft_tx_states[tx]->bit++;// go to next bit
}else{// UART frame is complete
timer_disable_irq(TIM(UART_SOFT_TX_TIMER),timer_interrupt[tx]);// enable timer IRQ for TX for this UART
if(!uart_soft_rx_states[rx]){// verify if receive port is not configured
continue;// skip if receive port is not defined it
}
if(uart_soft_rx_states[rx]->state!=gpio_get(uart_soft_rx_states[rx]->port,uart_soft_rx_states[rx]->pin)){// only do something if state changed
uart_soft_rx_states[rx]->state=gpio_get(uart_soft_rx_states[rx]->port,uart_soft_rx_states[rx]->pin);// save new state
if(uart_soft_rx_states[rx]->bit==0){// start bit edge detected
if(uart_soft_rx_states[rx]->state==0){// start bit has to be low
timer_set_oc_value(TIM(UART_SOFT_RX_TIMER),timer_oc[rx],timer_get_counter(TIM(UART_SOFT_RX_TIMER))+(rcc_ahb_frequency/uart_soft_rx_states[rx]->baudrate)*1.5);// set timer to sample data bit 0 in 1.5 bits
timer_clear_flag(TIM(UART_SOFT_RX_TIMER),timer_flags[rx]);// clear flag before enabling interrupt
uart_soft_rx_states[rx]->byte=0;// reset byte value
uart_soft_rx_states[rx]->bit++;// wait for first bit
}
}else{// data bit detected
timer_set_oc_value(TIM(UART_SOFT_RX_TIMER),timer_oc[rx],timer_get_counter(TIM(UART_SOFT_RX_TIMER))+(rcc_ahb_frequency/uart_soft_rx_states[rx]->baudrate)/2);// resync timer to half a bit (good for drifting transmission, bad if the line is noisy)
exti_reset_request(EXTI10|EXTI11|EXTI12|EXTI13|EXTI14|EXTI15);// clear interrupt flag for pin triggers this ISR (pin state will be checked independently)