I'm trying to integrate a shell into an STM32 project I'm working on. I used this library and followed a tutorial to get it working.
In the current implementation, the shell_get_char()
function arms the HAL_UART_Receive_IT
to receive a single byte. The HAL_UART_RxCpltCallback
function then calls shell_in()
to process the input. This approach works fine, but it has a limitation: it cannot detect arrow keys, which consist of three bytes.
To address this, I modified the code to use a ring buffer. This method works provided that shell_in() is called from the callback function (as it is in my current repo).
[edit]: By works I mean it reads single bytes, I still think it will be too slow to handle arrow keys this way.
Alternatively, I rewrote shell_get_byte()
to arm the HAL interrupt and pass the ring buffer data to shell_in()
. I also updated HAL_UART_RxCpltCallback()
to store the received character in the ring buffer and immediately rearm the HAL interrupt.
void shell_get_byte(char *c){
//Check that huart1 is ready to accept data
if (HAL_UART_GetState(&huart1) == HAL_UART_STATE_READY){
//Enable the UART interrupt
HAL_UART_Receive_IT(&huart1, (uint8_t *) c, 1);
}
if (rgbuffer_empty_c(&rgbuffer) == 0){
//HAL_UART_AbortReceive_IT(&huart1);
shell_in(rgbuffer_read_c(&rgbuffer));
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
//Verify the uart used
if(huart->Instance == USART1){
//Write to ring buffer
rgbuffer_write_c(&rgbuffer, shell_state.c);
HAL_UART_Receive_IT(&huart1, (uint8_t *) &shell_state.c, 1);
}
}
With this rewrite, I observe the following behavior:
- If I press only the Enter key, I get the expected behavior—a new line followed by the "/STM32" prompt.
- If I press any key, it is echoed to the terminal as expected. However, if I press the Enter key, the system freezes.
When I uncomment the following line in the shell_in()
function in shell.c:
while (shell_state.busy != 0); // Don't echo unless the interface is ready (this may be unnecessary here)
I observe different behavior. Now, when I press any key, that key is echoed, and then the system freezes. Pressing just the Enter key still behaves as expected. This leads me to believe that shell_state.busy
is not being cleared properly in HAL_UART_TxCpltCallback() After the shell_out()
DMA call.
I have limited troubleshooting tools, but I was able to toggle a GPIO pin every time shell_out()
is called and another in HAL_UART_TxCpltCallback()
. This means the LED states should match if shell_state.busy
is being set and reset properly—which they are. I have no idea where shell_state.busy
is being set without being reset.
[edit]: Added the Shell_out and HAL_UART_TxCpltCallback
void shell_out(char* buff, int length){
HAL_UART_Transmit_DMA(&huart1, (uint8_t *) buff, length);
//HAL_UART_Transmit_IT(&huart1, (uint8_t *) buff , length);
shell_state.busy = 1; //DMA Transfer in progress
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
//Verify which USART is being used
if(huart->Instance == USART1){
//Transfer complete
shell_state.busy = 0;
}
}
The only real difference is that shell_in()
is being called from the shell_get_char()
function instead of from the HAL_UART_RxCpltCallback()
function, but I can't figure out why that difference would matter.
Instead of copying all my code here, This is a link to the repo. All my source code is in the Core directly and the Shell code is in the STM_SHELL directory
I'm trying to integrate a shell into an STM32 project I'm working on. I used this library and followed a tutorial to get it working.
In the current implementation, the shell_get_char()
function arms the HAL_UART_Receive_IT
to receive a single byte. The HAL_UART_RxCpltCallback
function then calls shell_in()
to process the input. This approach works fine, but it has a limitation: it cannot detect arrow keys, which consist of three bytes.
To address this, I modified the code to use a ring buffer. This method works provided that shell_in() is called from the callback function (as it is in my current repo).
[edit]: By works I mean it reads single bytes, I still think it will be too slow to handle arrow keys this way.
Alternatively, I rewrote shell_get_byte()
to arm the HAL interrupt and pass the ring buffer data to shell_in()
. I also updated HAL_UART_RxCpltCallback()
to store the received character in the ring buffer and immediately rearm the HAL interrupt.
void shell_get_byte(char *c){
//Check that huart1 is ready to accept data
if (HAL_UART_GetState(&huart1) == HAL_UART_STATE_READY){
//Enable the UART interrupt
HAL_UART_Receive_IT(&huart1, (uint8_t *) c, 1);
}
if (rgbuffer_empty_c(&rgbuffer) == 0){
//HAL_UART_AbortReceive_IT(&huart1);
shell_in(rgbuffer_read_c(&rgbuffer));
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
//Verify the uart used
if(huart->Instance == USART1){
//Write to ring buffer
rgbuffer_write_c(&rgbuffer, shell_state.c);
HAL_UART_Receive_IT(&huart1, (uint8_t *) &shell_state.c, 1);
}
}
With this rewrite, I observe the following behavior:
- If I press only the Enter key, I get the expected behavior—a new line followed by the "/STM32" prompt.
- If I press any key, it is echoed to the terminal as expected. However, if I press the Enter key, the system freezes.
When I uncomment the following line in the shell_in()
function in shell.c:
while (shell_state.busy != 0); // Don't echo unless the interface is ready (this may be unnecessary here)
I observe different behavior. Now, when I press any key, that key is echoed, and then the system freezes. Pressing just the Enter key still behaves as expected. This leads me to believe that shell_state.busy
is not being cleared properly in HAL_UART_TxCpltCallback() After the shell_out()
DMA call.
I have limited troubleshooting tools, but I was able to toggle a GPIO pin every time shell_out()
is called and another in HAL_UART_TxCpltCallback()
. This means the LED states should match if shell_state.busy
is being set and reset properly—which they are. I have no idea where shell_state.busy
is being set without being reset.
[edit]: Added the Shell_out and HAL_UART_TxCpltCallback
void shell_out(char* buff, int length){
HAL_UART_Transmit_DMA(&huart1, (uint8_t *) buff, length);
//HAL_UART_Transmit_IT(&huart1, (uint8_t *) buff , length);
shell_state.busy = 1; //DMA Transfer in progress
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
//Verify which USART is being used
if(huart->Instance == USART1){
//Transfer complete
shell_state.busy = 0;
}
}
The only real difference is that shell_in()
is being called from the shell_get_char()
function instead of from the HAL_UART_RxCpltCallback()
function, but I can't figure out why that difference would matter.
Instead of copying all my code here, This is a link to the repo. All my source code is in the Core directly and the Shell code is in the STM_SHELL directory
Share Improve this question edited Mar 3 at 3:53 Lpaulson asked Mar 2 at 22:07 LpaulsonLpaulson 2293 silver badges12 bronze badges 7 | Show 2 more comments1 Answer
Reset to default 0I'm planning on using the same library for another one of my STM32 projects. If you are using the following library from Nefastor: https://nefastor/microcontrollers/stm32/libraries/stm-shell/
The author states that they will answer questions, have you tried leaving them a comment?
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745116706a4612169.html
UART_IT_RXNE
) and write your own ISR, and ditch the HAL. – pmacfarlane Commented Mar 2 at 22:42HAL_UART_Receive_IT()
for every character, and also having to go through the entire HAL callback mechanism for every character, is not fun. You should go look at those functions if you haven't already. – pmacfarlane Commented Mar 2 at 23:02