cancel
Showing results for 
Search instead for 
Did you mean: 

What's wrong with my half-duplex (receive only) software UART?

arnold_w
Senior II
Posted on June 09, 2016 at 14:20

I am working with the Discovery Development Board and I would like to receive data over a software UART. In the code below I would expect to receive 8 timer interrupts if only 1 byte is transmitted, but 100 microseconds after the last bit I receive an extra timer interrupt. Does anybody know why? Other than that, the UART seems to works fine.

000 #define TEST_PIN GPIO_PIN_15
001 #define TEST_PORT GPIOC
002 #define TOGGLE_TEST_PIN_AT_SAMPLING() SET_PIN_HIGH(TEST_PORT, TEST_PIN); SET_PIN_LOW(TEST_PORT, TEST_PIN); \
003 SET_PIN_HIGH(TEST_PORT, TEST_PIN); SET_PIN_LOW(TEST_PORT, TEST_PIN)
004 
005 #define Rx_PIN GPIO_PIN_11
006 #define Rx_PORT GPIOC
007 #define Rx_PIN_FLAG 0x0800
008 #define RECEIVE_EVENT_ARG LOW_LEVEL_EVENT__UART2_SW_BYTE_RECEIVED
009 #define EXTERNAL_INT EXTI15_10_IRQn
010 #define EXTERNAL_INT_HANDLER EXTI15_10_IRQHandler
011 #define TIMER_INSTANCE TIM4
012 #define TIMER_INT TIM4_IRQn
013 #define TIMER_INT_HANDLER TIM4_IRQHandler
014 
015 
016 #define CLEAR_EXT_INT_FLAG_ON_Rx() __HAL_GPIO_EXTI_CLEAR_IT(Rx_PIN)
017 #define ENABLE_EXT_INT_ON_Rx() HAL_NVIC_EnableIRQ(EXTERNAL_INT)
018 #define DISABLE_EXT_INT_ON_Rx() HAL_NVIC_DisableIRQ(EXTERNAL_INT)
019 
020 #define START_TIMER() (TIMER_INSTANCE->CR1 |= TIM_CR1_CEN)
021 #define STOP_TIMER() (TIMER_INSTANCE->CR1 &= ~TIM_CR1_CEN)
022 #define TIMER_INT_FLAG (TIMER_INSTANCE->SR & 0x0001)
023 #define ENABLE_TIMER_INT() 
do
{ TIMER_INSTANCE->DIER |= TIM_DIER_UIE; HAL_NVIC_EnableIRQ(TIMER_INT); } 
while
(0)
024 #define DISABLE_TIMER_INT() 
do
{ TIMER_INSTANCE->DIER &= ~TIM_DIER_UIE; HAL_NVIC_DisableIRQ(TIMER_INT); } 
while
(0)
025 #define CLEAR_TIMER_INT_FLAG() (TIMER_INSTANCE->SR &= ~TIM_SR_UIF)
026 #define SET_TIMER_PERIOD(period) (TIMER_INSTANCE->ARR = period)
027 #define SET_COUNTER_VALUE(value) (TIMER_INSTANCE->CNT = value)
028 #define SET_PRE_SCALAR_1() 
do
{ TIMER_INSTANCE->PSC = 0; TIMER_INSTANCE->EGR = TIM_EGR_UG; } 
while
(0)
029 
030 #define DUMMY_INT CAN2_RX1_IRQn
031 #define DUMMY_INT_HANDLER CAN2_RX1_IRQHandler
032 #define ENABLE_DUMMY_INT() (HAL_NVIC_EnableIRQ(DUMMY_INT))
033 #define CLEAR_DUMMY_INT_FLAG() (HAL_NVIC_ClearPendingIRQ(DUMMY_INT))
034 #define ISSUE_DUMMY_INT() NVIC->STIR = DUMMY_INT
035 
036 
037 
static
EventCallback_t ByteReceivedCallback_ = (EventCallback_t)NULL;
038 
static
uint32_t timerPeriod;
039 
static
uint32_t timerPeriodTimesOnePointFive;
040 
static
uint8_t idleState_;
041 
042 
043 
void
UART2_SW_Configuration(uint8_t idleState)
044 {
045 idleState_ = idleState;
046 
047 GPIO_InitTypeDef GPIO_InitStructure;
048 GPIO_InitStructure.Pin = Rx_PIN;
049 
if
(idleState_ == 0)
050 {
051 GPIO_InitStructure.Pull = GPIO_PULLDOWN;
052 GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
053 }
054 
else
055 {
056 GPIO_InitStructure.Pull = GPIO_PULLUP;
057 GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
058 }
059 GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
060 GPIO_InitStructure.Alternate = 0;
061 HAL_GPIO_Init(Rx_PORT, &GPIO_InitStructure);
062 
063 SET_PRE_SCALAR_1();
064 SET_TIMER_PERIOD(0xFFFFFFFF);
065 
066 HAL_NVIC_SetPriority(DUMMY_INT, 2, 0);
067 HAL_NVIC_SetPriority(EXTERNAL_INT, 1, 0);
068 HAL_NVIC_SetPriority(TIMER_INT, 0, 0);
069 
070 GPIO_InitStructure.Pin = TEST_PIN;
071 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
072 GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
073 GPIO_InitStructure.Pull = GPIO_NOPULL;
074 GPIO_InitStructure.Alternate = 0;
075 HAL_GPIO_Init(TEST_PORT, &GPIO_InitStructure);
076 SET_PIN_LOW(TEST_PORT, TEST_PIN);
077 
078 ENABLE_DUMMY_INT();
079 CLEAR_EXT_INT_FLAG_ON_Rx();
080 ENABLE_EXT_INT_ON_Rx();
081 }
082 
083 
084 
void
UART2_SW_SetCallback(EventCallback_t ByteReceivedCallback)
085 {
086 
if
(ByteReceivedCallback == (EventCallback_t)NULL)
087 {
088 ByteReceivedCallback_ = (EventCallback_t)NULL;
089 DISABLE_EXT_INT_ON_Rx();
090 }
091 
else
092 {
093 ByteReceivedCallback_ = ByteReceivedCallback;
094 ENABLE_EXT_INT_ON_Rx();
095 }
096 }
097 
098 
099 
void
UART2_SW_SetBaudRate(uint32_t baudRate)
100 {
101 timerPeriod = GET_TIMER_FREQ(TIMER_INSTANCE)/baudRate;
102 timerPeriodTimesOnePointFive = (3 * ((uint32_t)timerPeriod)) >> 1;
103 }
104 
105 
106 
static
volatile
uint8_t bitCount = 0;
107 
static
volatile
uint8_t receivedByte = 0;
108 
static
volatile
uint8_t finishedReceivedByte = 0;
109 
static
uint8_t sampledValue;
110 
111 
void
EXTERNAL_INT_HANDLER(
void
)
112 {
113 SET_COUNTER_VALUE(0);
114 START_TIMER();
115 DISABLE_EXT_INT_ON_Rx();
116 SET_TIMER_PERIOD(timerPeriodTimesOnePointFive);
117 CLEAR_TIMER_INT_FLAG();
118 ENABLE_TIMER_INT();
119 bitCount = 0;
120 }
121 
122 
123 
void
TIMER_INT_HANDLER(
void
)
124 {
125 TOGGLE_TEST_PIN_AT_SAMPLING();
126 sampledValue = READ_PIN(Rx_PORT, Rx_PIN);
127 CLEAR_TIMER_INT_FLAG();
128 
if
(bitCount == 0)
129 {
130 SET_TIMER_PERIOD(timerPeriod);
131 receivedByte = sampledValue;
132 bitCount++;
133 }
134 
else
if
((1 <= bitCount) && (bitCount <= 6))
135 {
136 receivedByte |= (sampledValue << bitCount);
137 bitCount++;
138 }
139 
else
140 {
141 STOP_TIMER();
142 DISABLE_TIMER_INT();
143 SET_TIMER_PERIOD(0xFFFFFFFF);
144 finishedReceivedByte = receivedByte | (sampledValue << 7);
145 
if
(idleState_ == 0)
146 {
147 finishedReceivedByte = ~finishedReceivedByte;
148 }
149 
if
(bitCount == 7)
150 {
151 ISSUE_DUMMY_INT();
152 }
153 
if
(ByteReceivedCallback_ != (EventCallback_t)NULL)
154 {
155 CLEAR_EXT_INT_FLAG_ON_Rx();
156 ENABLE_EXT_INT_ON_Rx();
157 }
158 }
159 }
160 
161 
162 
void
DUMMY_INT_HANDLER(
void
)
163 {
164 
if
(ByteReceivedCallback_ != (EventCallback_t)NULL)
165 {
166 (
void
)ByteReceivedCallback_((uint32_t)RECEIVE_EVENT_ARG, (uint32_t)finishedReceivedByte);
167 }
168 }

10 REPLIES 10
Posted on June 14, 2016 at 14:32

Doesn't the F4 have enough real USARTs?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..