You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
6.8 KiB
171 lines
6.8 KiB
// inspired by AN4655 |
|
// http://www.st.com/content/ccc/resource/technical/document/application_note/3d/80/91/f9/4c/25/4a/26/DM00160482.pdf/files/DM00160482.pdf/jcr:content/translations/en.DM00160482.pdf |
|
// last in page http://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32l0-series/stm32l0x2/stm32l052c6.html |
|
/* |
|
|
|
This example shows how to control both transmit and receive processes by software, based on HW events. |
|
|
|
Overflow and IO capture events of a single Capture & Compare timer is used to control timing of emulation of UART input sampling and |
|
output handling of the Rx and Tx signals. The associated input capture pin is dedicated to receive data. Any general-purpose output |
|
pin or associated output compare pin can be used for data transmission. The timer overflow period is set to the channel half bit rate |
|
by setting the timer auto reload register. |
|
|
|
illustrates the timing diagram. |
|
|
|
Figure 3. UART duplex channel based on timer capture events |
|
|
|
Transmission process control is based on regular interrupts from the timer overflow events. |
|
After data for transmission is stored into dedicated variable (transmit buffer simulated by SW), an internal transmission request appears and |
|
the nearest overflow interrupt is used to start a new transmission (maximum latency for transmission start could be half a bit period). |
|
This is because the same timer is used for control both transmit and receive processes not synchronized normally. Every even timer overflow |
|
event interrupt controls the consecutive edge changes of the transmitted signal on the dedicated output pin until the end of the frame |
|
transmission. Odd overflow interrupts are discarded. |
|
|
|
The receive process uses both input capture and output compare feature of the same timer and its dedicated pin. |
|
Initially, the input capture is performed at the pin. After detecting the first falling edge, the value captured in the |
|
capture register is then used for compare purposes because the input pin functionality is switched to output compare mode (without |
|
affecting any output GPIO capability since the pin still stays in input mode). Due to the half-a-bit overflow period of the timer, the nearest |
|
output compare event points to the middle of the first receive bit (start bit). Sampling can be simulated by three consecutive reading of the |
|
input pin level at that moment and if, for each of them, a low level is detected, the correctly received start bit is evaluated. The receive |
|
process then continues by watching every next odd output compare event. The same three point sampling method can be performed with noise |
|
detection logic here and for all the other received data bits until the end of the current receive frame. All even compare interrupts are |
|
discarded. After the stop bits of the frame are sampled, the Rx pin is switched back to input capture mode and waits for the next frame |
|
start condition. The detection of noise while the stop bits are being sampled should cause a frame error. If a noise is detected during start |
|
bit, the receive process should be aborted and the Rx pin switched back to input capture mode while waiting for the next falling edge capture. |
|
|
|
User can build an API interface upon this low level HW abstraction level. It can include the UART channel initialization, enable and disabl |
|
e Rx and Tx channels, read and write the data flow (e.g. control the data buffers) and check the transactions’ status. Size of data, parity |
|
control number of stop bits or other control can be solved on pre-compilation level by conditional compilation to speed up the code when |
|
these features are not used. |
|
|
|
|
|
(C) |
|
|
|
in case of RevoMini we have pins |
|
|
|
14, // PC8 T8/3 - Soft_scl or soft_tx |
|
15, // PC9 T8/4 - Soft_sda or soft_rx |
|
|
|
*/ |
|
|
|
#pragma once |
|
|
|
#if defined(BOARD_SOFTSERIAL_RX) && defined(BOARD_SOFTSERIAL_TX) |
|
|
|
#include <AP_HAL_F4Light/AP_HAL_F4Light.h> |
|
|
|
#include <usart.h> |
|
#include <gpio_hal.h> |
|
#include <pwm_in.h> |
|
#include "Scheduler.h" |
|
#include "GPIO.h" |
|
|
|
#define DEFAULT_TX_TIMEOUT 10000 |
|
|
|
#define SS_DEBUG |
|
|
|
#define SSI_RX_BUFF_SIZE 64 |
|
#define SSI_TX_BUFF_SIZE 64 |
|
#define SS_MAX_RX_BUFF (SSI_RX_BUFF_SIZE - 1) // RX buffer size |
|
#define SS_MAX_TX_BUFF (SSI_TX_BUFF_SIZE - 1) // TX buffer size |
|
|
|
extern const struct TIM_Channel PWM_Channels[]; |
|
|
|
class F4Light::SerialDriver : public AP_HAL::UARTDriver { |
|
public: |
|
SerialDriver( uint8_t tx_pin, uint8_t rx_pin, bool inverseLogic) |
|
:_inverse(inverseLogic) |
|
, _initialized(false) |
|
, _blocking(true) |
|
, txSkip(false) |
|
, rxSkip(false) |
|
, activeRX(false) |
|
, activeTX(false) |
|
,_tx_pin(tx_pin) |
|
,_rx_pin(rx_pin) |
|
, tx_pp(PIN_MAP[tx_pin]) |
|
, rx_pp(PIN_MAP[rx_pin]) |
|
, timer(rx_pp.timer_device) |
|
, channel(rx_pp.timer_channel) |
|
{ |
|
} |
|
|
|
|
|
/* F4Light implementations of UARTDriver virtual methods */ |
|
void begin(uint32_t b); |
|
void begin(uint32_t baud, uint16_t rxS, uint16_t txS) { begin(baud); } |
|
void end(); |
|
void flush(); |
|
|
|
bool inline is_initialized(){ return _initialized; } |
|
|
|
void inline set_blocking_writes(bool blocking) { _blocking=blocking; } |
|
bool tx_pending(); |
|
|
|
/* F4Light implementations of Stream virtual methods */ |
|
uint32_t available() override; |
|
uint32_t txspace() override; |
|
int16_t read() override; |
|
|
|
/* Empty implementations of Print virtual methods */ |
|
size_t write(uint8_t c); |
|
size_t write(const uint8_t *buffer, size_t size); |
|
|
|
private: |
|
|
|
bool _inverse; |
|
bool _initialized; |
|
bool _blocking; |
|
|
|
uint16_t bitPeriod; |
|
|
|
#ifdef SS_DEBUG |
|
volatile uint8_t bufferOverflow; |
|
#endif |
|
|
|
volatile int8_t rxBitCount; |
|
volatile uint16_t receiveBufferWrite; |
|
volatile uint16_t receiveBufferRead; |
|
volatile uint8_t receiveBuffer[SSI_RX_BUFF_SIZE]; |
|
uint8_t receiveByte; |
|
|
|
volatile int8_t txBitCount; |
|
uint16_t transmitBufferWrite; |
|
volatile uint16_t transmitBufferRead; |
|
uint8_t transmitBuffer[SSI_RX_BUFF_SIZE]; |
|
|
|
bool txSkip; |
|
bool rxSkip; |
|
|
|
bool activeRX; |
|
bool activeTX; |
|
|
|
uint8_t _tx_pin; |
|
uint8_t _rx_pin; |
|
const stm32_pin_info &tx_pp; |
|
const stm32_pin_info &rx_pp; |
|
|
|
const timer_dev *timer; |
|
const timer_Channel channel; |
|
|
|
// Clear pending interrupt and enable receive interrupt |
|
// Note: Clears pending interrupt |
|
inline void txEnableInterrupts() { |
|
timer->regs->SR &= ~TIMER_SR_UIF; |
|
timer_enable_irq(timer, TIMER_UPDATE_INTERRUPT); |
|
} |
|
|
|
// Mask transmit interrupt |
|
inline void txDisableInterrupts() { |
|
timer_disable_irq(timer, TIMER_UPDATE_INTERRUPT); |
|
} |
|
|
|
void rxSetCapture(); |
|
void rxSetCompare(); |
|
|
|
void txNextBit( /* TIM_TypeDef *tim */ ); |
|
void rxNextBit( /* TIM_TypeDef *tim */ ); |
|
|
|
}; |
|
|
|
#endif // defined(BOARD_SOFTSERIAL_RX) && defined(BOARD_SOFTSERIAL_TX)
|
|
|