Ковыряю сейчас STM32 с libopencm3. Попытался расширить пример usart_irq (наверное, нужно было ещё посмотреть на usart_irq_printf, но его я пока не открывал). Теперь у меня есть буфер для отправки и для приёма строк.
Кода не очень много, потому, думаю, можно выложить весь.
#include <string.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h>
#define BS 16 // buffer size (number of strings)
char request[256]; // string to send to modem
char response[BS][256]; // last BS strings received from modem
int row, ch; // number of string and last character received from modem
uint8_t last = 'A'; // last character received from modem
int step = 0;
static void clock_setup(void) {
rcc_clock_setup_in_hse_8mhz_out_72mhz();
/* Enable clocks for GPIO port A (for GPIO_USART1_TX) and USART1. */
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_USART1);
}
static void usart_setup(void) {
/* Enable the USART1 interrupt. */
nvic_enable_irq(NVIC_USART1_IRQ);
/* Setup GPIO pin GPIO_USART1_RE_TX on GPIO port A for transmit. */
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
/* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port A for receive. */
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
/* Setup UART parameters. */
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_set_mode(USART1, USART_MODE_TX_RX);
/* Enable USART1 Receive interrupt. */
USART_CR1(USART1) |= USART_CR1_RXNEIE;
/* Finally enable the USART. */
usart_enable(USART1);
}
static void gpio_setup(void) {
gpio_set(GPIOA, GPIO1);
/* Setup GPIO1 (in GPIO port A) for LED use. */
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO1);
}
static void wait(void) {
int i;
for (i = 0; i < 800000; i++) /* Wait a bit. */
__asm__("nop");
}
static int row_num(int n) {
// use this function to get correct row offset
// row_num(0) - latest row, row_num(1) - second latest row, etc.
int r = row - n;
if (r < 0) {
return r + BS;
} else {
return r;
}
}
static void action_select(void) {
if (strcmp(response[row], "OK") == 0) {
gpio_toggle(GPIOA, GPIO1);
wait();
gpio_toggle(GPIOA, GPIO1);
wait();
gpio_toggle(GPIOA, GPIO1);
wait();
gpio_toggle(GPIOA, GPIO1);
} else if (strcmp(response[row], "ERROR") == 0) {
gpio_toggle(GPIOA, GPIO1);
wait();
gpio_toggle(GPIOA, GPIO1);
} else if (strcmp(response[row], "PRINT") == 0) {
int i;
strcpy(request, "\r\n");
for (i = 0; i < BS; i++) {
char num[5] = { '[', i < 10 ? '0' + i : 'A' + i - 10, ']', ':', ' ' };
strcat(request, num);
strcat(request, response[row_num(i)]);
strcat(request, "\r\n");
}
}
}
static void set_send(void) {
/* Enable transmit interrupt so it sends back the data. */
USART_CR1(USART1) |= USART_CR1_TXEIE;
}
static void unset_send(void) {
/* Disable the TXE interrupt as we don't need it anymore. */
USART_CR1(USART1) &= ~USART_CR1_TXEIE;
}
static void send(void) {
if (request[0] != 0) {
int i = 0;
uint8_t s = '0';
while (s = request[i++], s != 0) {
usart_wait_send_ready(USART1);
usart_send(USART1, s);
}
usart_wait_send_ready(USART1);
usart_send(USART1, '\r');
// new line here should be commented out in production
usart_wait_send_ready(USART1);
usart_send(USART1, '\n');
request[0] = 0;
} else {
// echo last char back (should also be commented out in production)
usart_wait_send_ready(USART1);
usart_send(USART1, last);
if (last == '\r') {
usart_wait_send_ready(USART1);
usart_send(USART1, '\n');
}
}
unset_send();
}
static void receive(void) {
/* Retrieve the data from the peripheral. */
last = usart_recv(USART1);
response[row][ch] = last;
if (response[row][ch] == '\r') {
response[row][ch] = '\0';
action_select();
if (ch > 1) row++;
ch = 0;
if (row == BS) row = 0;
} else if (response[row][ch] != '\n') {
ch++;
}
set_send();
}
void usart1_isr(void) {
/* Check if we were called because of RXNE. */
if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) &&
((USART_SR(USART1) & USART_SR_RXNE) != 0)) {
receive();
}
/* Check if we were called because of TXE. */
if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) &&
((USART_SR(USART1) & USART_SR_TXE) != 0)) {
send();
}
}
static void send_request(char *str) {
strcpy(request, str);
send();
}
int main(void) {
clock_setup();
gpio_setup();
usart_setup();
gpio_set(GPIOA, GPIO1);
send_request("HELLO\r");
/* Wait forever and do nothing. */
while (1)
__asm__("nop");
return 0;
}
HELLO
OK
ERROR
PRINT
[0]: PRINT
[1]: ERROR
[2]: OK
[3]:
[4]:
[5]:
[6]:
[7]:
[8]:
[9]:
[A]:
[B]:
[C]:
[D]:
[E]:
[F]:
Я подумал, что достаточно после инициализации в main добавить следующее:
gpio_set(GPIOA, GPIO1);
send_request("HELLO\r");
while (strcmp(response[row_num(0)], "WORLD") != 0)
__asm__("nop");
gpio_clear(GPIOA, GPIO1);
send_request("TRUE\r");
HELLO
WORLD
PRINT
[0]:
PRINT
[1]:
WORLD
[2]:
[3]:
[4]: