Тестовое окружение:
Em::Blocks 2.10 / arm-gcc / newlib
STM32-vldiscovery / STM32F100RBT6
размер стека - 2 кБ.
Функция _read() реализована в двух вариантах:
Спойлер
Код: Выделить всё
#ifdef CORRECT_READ
int _read(int fd,void *buf, size_t count)
{
size_t k;
k=0;
usart_byte_received=0; //This flag gets set in UART RX interrupt handler
set_LED(LED_B_PC,1); //Blue LED on Discovery
sprintf(debug_str,"_read() called with fd = %i, count = %i\r\n",fd,count);
USART1_TransmitString(debug_str);
while (k<count)
{
if (usart_byte_received)
{
((uint8_t *)buf)[k]=usart_byte;
k++;
if (usart_byte==0x0D)
{
((uint8_t *)buf)[k]=0x0A;
k++;
usart_byte_received=0;
return k;
}
usart_byte_received=0;
}
}
set_LED(LED_B_PC,0);
return k;
}
#else
int _read(int fd,void *buf, size_t count)
{
sprintf(debug_str,"_read() called with fd = %i, count = %i\r\n",fd,count);
USART1_TransmitString(debug_str);
while (!usart_byte_received);
*((uint8_t*)buf)=usart_byte;
usart_byte_received=0;
return 1;
}
#endif
попытка считать значения из UART по паттерну "%c%i%i" демонстрирует следующее поведение:
- первый вызов завершается успешно;
- второй вызов завершается после первого прочитанного байта, в процессе scanf(), по всей видимости, портит стек.
Полный код экспериментальной программы (одна из версий, в процессе детали менялись, но общая структура оставалась неизменной):
gpio_macros_f100.h
Спойлер
Код: Выделить всё
#ifndef GPIO_MACROS_F100_H_INCLUDED
#define GPIO_MACROS_F100_H_INCLUDED
//Pin types for input and output
#define IN_ANALOG 0x00
#define IN_FLOATING 0x01
#define IN_PULLED 0x02
#define OUT_PP 0x00
#define OUT_OD 0x01
#define OUT_AF_PP 0x02
#define OUT_AF_OD 0x03
//Pin modes
#define MODE_IN 0x00
#define MODE_OUT_2MHz 0x02
#define MODE_OUT_10MHz 0x01
#define MODE_OUT_50MHz 0x03
//Macros for GPIO_CRL and GPIO_CRH
#define PIN_CONFCRL(pin_no,pin_mode,pin_type) ((((pin_type) << 2) | (pin_mode)) << ((pin_no)*4))
#define PIN_CONFCRH(pin_no,pin_mode,pin_type) ((((pin_type) << 2) | (pin_mode)) << ((pin_no - 8)*4))
//Macros for GPIO_BSRR
#define BSRR_SET(pin_no) (1<<(pin_no))
#define BSRR_RESET(pin_no) ((1<<(pin_no))<<16)
#define PIN_MASK(pin_no) (1<<(pin_no))
#endif /* GPIO_MACROS_F100_H_INCLUDED */
Спойлер
Код: Выделить всё
#include "stm32f10x.h"
#include "stdio.h"
#include "gpio_macros_f100.h"
/**
HSE: 8MHz
CPU clock: PLL, 24 MHz
USART: 8N1, 921 kBaud or 115.2 kBaud
*/
#define USART_115200 1
//#define CORRECT_READ 1
#define USART1_TX_PA 9
#define USART1_RX_PA 10
#define LED_G_PC 9
#define LED_B_PC 8
volatile uint8_t usart_byte_received=0,usart_byte;
char debug_str[255];
void set_LED(uint8_t led,uint8_t state)
{
if ((led==LED_B_PC) || (led==LED_G_PC))
{
if (state)
{
GPIOC->BSRR=PIN_MASK(led);
}
else
{
GPIOC->BSRR=PIN_MASK(led)<<16;
}
}
}
void delay_cycles(uint32_t cycles)
{
volatile uint32_t k;
for (k=0; k<cycles; k++)
{
}
}
void USART1_IRQHandler(void)
{
volatile uint8_t b;
b=USART1->DR;
if (!usart_byte_received)
{
usart_byte=b;
usart_byte_received=1;
}
}
void USART1_TransmitByte(uint8_t byte)
{
while (!(USART1->SR & USART_SR_TXE))
{
}
USART1->DR=byte;
}
void USART1_TransmitBuffer(uint8_t* buffer,uint32_t len)
{
volatile uint32_t k;
for (k=0; k<len; k++)
{
USART1_TransmitByte(buffer[k]);
}
}
void USART1_TransmitString(uint8_t* str)
{
int16_t counter;
counter=0;
while ((str[counter]!=0) && (counter<255))
{
USART1_TransmitByte(str[counter]);
counter++;
}
}
int _write(int fd, const void *buf, size_t count)
{
USART1_TransmitBuffer((uint8_t *)buf,count);
return count;
}
#define CORRECT_READ 1
#ifdef CORRECT_READ
int _read(int fd,void *buf, size_t count)
{
size_t k;
k=0;
usart_byte_received=0;
set_LED(LED_B_PC,1);
sprintf(debug_str,"_read() called with fd = %i, count = %i\r\n",fd,count);
USART1_TransmitString(debug_str);
while (k<count)
{
if (usart_byte_received)
{
((uint8_t *)buf)[k]=usart_byte;
k++;
if (usart_byte==0x0D)
{
((uint8_t *)buf)[k]=0x0A;
k++;
usart_byte_received=0;
return k;
}
usart_byte_received=0;
}
}
set_LED(LED_B_PC,0);
return k;
}
#else
int _read(int fd,void *buf, size_t count)
{
sprintf(debug_str,"_read() called with fd = %i, count = %i\r\n",fd,count);
USART1_TransmitString(debug_str);
while (!usart_byte_received);
*((uint8_t*)buf)=usart_byte;
usart_byte_received=0;
return 1;
}
#endif
int main(void)
{
int p1,p2,p3;
char s[255];
char c;
int scanf_return_value;
RCC->APB2ENR=RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
//Free JTAG pins, except those used for SWD
AFIO->MAPR=AFIO_MAPR_SWJ_CFG_1;
GPIOA->CRH=PIN_CONFCRH(USART1_TX_PA,MODE_OUT_10MHz,OUT_AF_PP) | PIN_CONFCRH(USART1_RX_PA,MODE_IN,IN_PULLED);
GPIOA->ODR=PIN_MASK(USART1_RX_PA); //Enable pullup on USART RX pin
GPIOC->CRH=PIN_CONFCRH(LED_G_PC,MODE_OUT_2MHz,OUT_PP) | PIN_CONFCRH(LED_B_PC,MODE_OUT_2MHz,OUT_PP);
//USART1 setup
USART1->CR1=USART_CR1_UE;
USART1->CR2=0;
#ifdef USART_115200
USART1->BRR=(13 << 4) | 0;
#else
//k = 1.63 ~= 1 + (10/16)
//baud = 921000
USART1->BRR=(1 << 4) | 10;
#endif
USART1->CR1|=USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
NVIC_EnableIRQ(USART1_IRQn);
set_LED(LED_G_PC,1);
while (1)
{
printf("Enter data, char/int/int: \r\n");
scanf_return_value=scanf("%c%i%i",&c,&p1,&p2);
if (scanf_return_value<3)
{
printf("Weird scanf()! Returned %i \r\n",scanf_return_value);
}
else
{
printf("scanf() returned %i. Values: %c,%i,%i\r\n",scanf_return_value,c,p1,p2);
}
delay_cycles(500000);
}
}
- с использованием второй версии _read(), возвращающей по байту за раз. Видно, что второй вызов scanf() вылетает после первого принятого байта.
Код: Выделить всё
Enter data, char/int/int:
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
scanf() returned 3. Values: a,12,34
Enter data, char/int/int:
_read() called with fd = 0, count = 1024
Weird scanf()! Returned 1
Enter data, char/int/int:
_read() called with fd = 0, count = 1024
_read() called with fd = 0, count = 1024
Мой друг m08pvv, тоже заинтересовавшись описанным явлением, обнаружил, что, по-видимому, для чтения паттернов "%c" и "%s" применяется один и тот же код. Возможно, это является источником проблемы.
