AnsweredAssumed Answered

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

Question asked by arnold_w on Jun 9, 2016
Latest reply on Jun 14, 2016 by Clive One
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        }

Outcomes