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 RX pins
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 sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq(NVIC_TIM_IRQ(UART_SOFT_TX_TIMER));// allow interrupt for timer
constuint32_ttimer_flags[4]={TIM_SR_CC1IF,TIM_SR_CC2IF,TIM_SR_CC3IF,TIM_SR_CC4IF};/**< the interrupt flags for the compare units */
constuint32_ttimer_interrupt[4]={TIM_DIER_CC1IE,TIM_DIER_CC2IE,TIM_DIER_CC3IE,TIM_DIER_CC4IE};/**< the interrupt enable for the compare units */
constenumtim_oc_idtimer_oc[4]={TIM_OC1,TIM_OC2,TIM_OC3,TIM_OC4};/**< the output compares for the compare units */
for(uint8_trx=0;rx<4;rx++){
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
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
constuint32_ttimer_flags[4]={TIM_SR_CC1IF,TIM_SR_CC2IF,TIM_SR_CC3IF,TIM_SR_CC4IF};/**< the interrupt flags for the compare units */
constuint32_ttimer_interrupt[4]={TIM_DIER_CC1IE,TIM_DIER_CC2IE,TIM_DIER_CC3IE,TIM_DIER_CC4IE};/**< the interrupt enable for the compare units */
constenumtim_oc_idtimer_oc[4]={TIM_OC1,TIM_OC2,TIM_OC3,TIM_OC4};/**< the output compares for the compare units */
for(uint8_trx=0;rx<4;rx++){
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
timer_enable_irq(TIM(UART_SOFT_RX_TIMER),timer_interrupt[rx]);// enable timer IRQ for RX0
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)