Loading...
 
Skip to main content

System Workbench for STM32


__io_getchar implementation for getchar() has a problem

Please forgive me for bothering you yet again but I seem to have run into another issue.

I am attempting to implement getchar() and putchar() using io_getchar() and io_putchar() and I am running into a strange issue.

When I make a call to getchar() it calls srget_r() who calls srefill_r() who calls __sread() who calls _read_r() who calls _read().

The problem is that the _read function (in syscalls.c) is getting called with a length of 1024. Since the initial call was to getchar() a single character should have been requested.

This is causing my program to both crash and/or lock up due to over running my 1 byte buffer.

Am I missing something in my implementation of io_getchar? I have included the _read function from syscalls.c (found in the STM32Cube examples directory) and my io_getchar function.

Prior to implementing __io_getchar() I made sure that HAL_UART_Receive_DMA() is working properly.

In the mean time I am modifying _read to ignore the len parameter and only read a single byte.

int _read (int file, char *ptr, int len)
{
int DataIdx;

for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}

return len;
}

int __io_getchar( void )
{
uint8_t Byte;

HAL_UART_Receive_DMA( &huart6, &Byte, 1 );
RxReady = FALSE;
while ( !RxReady );
return (int)Byte;
}

I ran into the same problem using the HAL_UART_Receive_() function (No DMA).

I implemented your workaround by setting 'len' to 1 inside the _read() function in the syscalls.c module. This works. But without the DMA, the function does not block as it should.

I fixed this by waiting for success in my __io_getchar() function.

int __io_getchar(void) {
HAL_StatusTypeDef Status = HAL_BUSY;
uint8_t Data;

while(Status != HAL_OK)
Status = HAL_UART_Receive(&huart6, &Data, 1, 10);

return(Data);
}

I also removed the increment of 'ptr' in the _read() function since I don't know if 'ptr' is reinitialized each time _read() is called.

I don't feel good about modifying the syscalls.c module that I didn't write but downloaded. It won't have my changes the next time I download it.


Just repied to topic with the same question:

Copy to clipboard
bool getchar(uint8_t * ch) { // check for overflow and clear if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE)) __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_ORE); if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) { *ch = huart1.Instance->RDR & 0x1FF; return true; } return false; } void _write(int file, char *ptr, int len) { HAL_UART_Transmit(&huart1, (uint8_t*) ptr, len, 10); }


The printf will call the _write function. You need to end it with \r\n or nothing will be printed.
I would like to know how to redirect the putc because this is not possible:

Copy to clipboard
if (sci1_get(&ch)) printf("%c", ch);

I gave up completely on using syscalls.c and the standard print functions and wrote my own (files attached below).

I did run into a interesting problem trying to get blocked input using DMA on the UART.

I tried waiting for the UART Recevie Data Not Empty flag to be set and then calling HAL_UART_Receive_DMA() for a single byte but apparently HAL_UART_Receive_DMA() flushes the UART prior to reading the UART so for input I use blocking input.

For completeness a String_GetsN() could be added to get a string/buffer of known length from the UART using DMA but I didn't need it so I didn't write it. 😊

Please note: I have not fully tested the interrupt driven code.

Since this only seems to allow attaching a single file the MyString.c and MyString.h files can be found here: https://www.dropbox.com/sh/wz300bkp0yfpg49/AABP0b3PVVNa2MXG_UIDX6xba?dl=0


 
Collapse/expand modules below