Нашёл ответ на свой вопрос. I2C на плате сделан программный..
Всем привет.
Занимаюсь реализацией TUI через UART на STM32F1xx с HAL. Описание функциональности:
- Неблокирующий ввод
- Завершение ввода при нажатии Enter
- При нажатии на Backspace предыдущий символ удаляется (при наличии)
- Видимые символы отображаются
Вывод также хочется реализовать через прерывания, если вызов функции был сделан не из обработчика другого прерывания (в таком случае реализуется блокирующий вывод).
При написании кода использую кольцевой буфер (ring/circular buffer) для хранения строк. Он представляет из себя отдельную библиотеку.
Вот код проекта:
static UART_HandleTypeDef *console_uart = NULL;
static char line_buffer[CONSOLE_MAX_RX_DATA_LENGTH];
static uint16_t line_len = 0;
// TX Buffer
static ring_buffer_t tx_buffer;
static volatile uint8_t tx_busy = 0;
static volatile uint8_t tx_byte;
// RX Buffer
static ring_buffer_t rx_buffer;
static volatile uint8_t rx_byte;
static volatile uint8_t rx_ready = 0;
static void console_rx_callback(UART_HandleTypeDef *);
static void console_tx_callback(UART_HandleTypeDef *);
uint8_t console_init(UART_HandleTypeDef *huart) {
if (huart == NULL || console_uart != NULL) {
return 1;
}
console_uart = huart;
ring_buffer_init(&tx_buffer);
tx_busy = 0;
ring_buffer_init(&rx_buffer);
rx_ready = 0;
HAL_UART_RegisterCallback(
console_uart,
HAL_UART_RX_COMPLETE_CB_ID,
console_rx_callback
);
HAL_UART_RegisterCallback(
console_uart,
HAL_UART_TX_COMPLETE_CB_ID,
console_tx_callback
);
HAL_UART_Receive_IT(console_uart, (uint8_t *) &rx_byte, 1);
return 0;
}
void console_print(const char *str) {
HAL_UART_Transmit(console_uart, (uint8_t *) str, strlen(str), 10);
// ring_buffer_write(&tx_buffer, (uint8_t *) str, strlen(str));
// if (tx_busy == 0) {
// tx_busy = 1;
// tx_byte = ring_buffer_pop(&tx_buffer);
// HAL_UART_Transmit_IT(console_uart, &tx_byte, 1);
// }
}
void console_clear() {
console_print("\033[2J\033[H");
}
// Берет на себя всю обработку символов: backspace, enter и echo
void console_poll() {
while (ring_buffer_get_length(&rx_buffer) > 0 && rx_ready == 0) {
uint8_t ch = ring_buffer_pop(&rx_buffer);
if ((ch == '\b' || ch == 0x7F) && line_len > 0) {
line_len--;
console_print("\b \b");
}
else if (ch == '\r' || ch == '\n') {
line_buffer[line_len] = '\0';
rx_ready = 1;
console_print("\r\n");
return;
}
else if (line_len < CONSOLE_MAX_RX_DATA_LENGTH - 1) {
line_buffer[line_len++] = ch;
char echo[2] = {ch, 0};
console_print(echo);
}
}
}
uint8_t console_ready() {
return rx_ready;
}
void console_read(char *buffer) {
if (buffer == NULL || rx_ready == 0) {
return;
}
strcpy(buffer, line_buffer);
rx_ready = 0;
line_len = 0;
line_buffer[0] = '\0';
}
static void console_tx_callback(UART_HandleTypeDef *console) {
if (ring_buffer_get_length(&tx_buffer) == 0) {
tx_busy = 0;
}
else {
tx_byte = ring_buffer_pop(&tx_buffer);
HAL_UART_Transmit_IT(console_uart, &tx_byte, 1);
}
}
static void console_rx_callback(UART_HandleTypeDef *console) {
ring_buffer_push(&rx_buffer, rx_byte);
HAL_UART_Receive_IT(console_uart, &rx_byte, 1);
}
Использование в приложении примерно такое:
while(1) {
console_poll();
if (console_ready()) {
console_read(consoleBuffer);
// Действия с console buffer
}
}
При подключении через утилиту screen на скорости 115200 выводит следующее (вводил просто '?'):
Rebooeot system ?. menu cm>> Unknoan oy en symenu cm
То есть вывод максимально ломаный.
Знающие люди, подскажите, пожалуйста, что не так с этим кодом и в чем именно проблема. Нейронки не помогают, а в DMA сейчас не планирую лезть - хочу сперва разобраться с прерываниями.
Благодарю за любую помощь, спасибо!