ARM7 printf зависает при попытке печати в UART
У меня проблемы с различными командами печати.
Каждый раз, когда я пытаюсь вызвать printf(), моя система просто зависает или иногда перезагружается.
У меня работает UART, и я могу нормально печатать в консоли с помощью UART_PutChar().
fprintf работает в простых случаях простой печати простой строки fprintf(stdout, "test\n");
однако отформатированные строки повесят мою систему fprintf(stdout, "test %d\n", 1);
Зависание также происходит, когда я пытаюсь распечатать данные из раздела.data
char* dataString = "test\n\0";
int main(){
fprintf(stdout, dataString);
}
printf будет работать, когда я буду печатать новые строки printf("\n");
printf будет печатать только новые строки, если я сделаю что-то вроде
fputc('B', stdin); //notice stdin
printf("test\n"); //prints newline
В некоторых случаях, когда fprintf терпит неудачу, он возвращает EOF (не могу вспомнить их сейчас, предоставит их завтра, если это станет актуальным)
(f) printf, кажется, вызывает putchar, и я перенаправил его на UART.
Любопытно, что я думаю, что это должно быть _write
или же _write_r
процедуры, предоставляемые newlib-nano (и printf их не вызывает).
В качестве IDE я использую EmBitz и предоставляемый им набор инструментов (arm-none-eabi). Процессор, который я использую - at91sam7x128. Я не могу отладить свою программу с помощью JTAG, поэтому мне нужно попробовать использовать только UART для отладки.
char* dataSection = "data\n\0";
char* dataSingle = "A";
int bssSection = 0;
int main(){
fprintf(stdout, "plain\n"); //works
fprintf(stdout, dataSingle); //works
fprintf(stdout, *(char*)(bssSection + 0x41)); //prints A, works
printf("\n"); //works
fprintf(stdout, "%d", 1); //hangs
fprintf(stdout, dataSection); //hangs
printf("plain printf\n"); //hangs
}
ОБНОВЛЕНИЕ стартовый скрипт: SAM7.s
/*********************************************************************
*
* Defines, used for the processor status register
*
**********************************************************************
*/
ARM_MODE_USER = 0x10 /* Normal User Mode */
ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */
ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */
ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */
ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */
ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */
ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */
ARM_MODE_MASK = 0x1F
I_BIT = 0x80 /* Disables IRQ when I bit is set */
F_BIT = 0x40 /* Disables FIQ when F bit is set */
/*********************************************************************
*
* Vector table
*
**********************************************************************
*/
.text
.global __vector
.global _exit
.extern Reset_Handler
.arm
.section .vectors, "ax"
__vector:
ldr pc,Reset_Addr /* RESET vector */
Reset_Addr: .word Reset_Handler
__vector_end:
/*********************************************************************
*
* Standard C (crt0) initialization function
*
**********************************************************************
*/
.global OS_GetStackInfo
.extern __low_level_init
.extern main
crt0:
/*
* Call __low_level_init to initiliaze hardware
* before calling c-standard startup
*/
ldr r0,=__low_level_init
mov lr, pc
bx r0
/*
* Relocate .data section
* (Copy from ROM to RAM)
*/
ldr r1, =_etext
ldr r2, =_data
ldr r3, =_edata
LoopRel:
cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo LoopRel
/*
* Clear .bss section
*/
ldr r1, =__bss_start__
ldr r2, =__bss_end__
ldr r3, =0
bss_clear_loop:
cmp r1, r2
strne r3, [r1], #+4
bne bss_clear_loop
/*
* Prepare and call main()
*/
mrs r0, cpsr
bic r0, r0, #(I_BIT | F_BIT) /* Enable FIQ and IRQ interrupt */
msr cpsr, r0
mov r0, #0 /* No arguments are passed to main */
mov r1, #0
ldr r2, =main
mov lr, pc
bx r2
_exit: b _exit /* We should never come to here, just for sureness. */
/*********************************************************************
*
* __low_level_init
*
**********************************************************************
*/
__low_level_init:
bx lr
.weak __low_level_init
/**********************************************************************
* Reset_Handler
*
* Execution starts here.
* After a reset, the mode is ARM, Supervisor, interrupts disabled.
*/
.global Reset_Handler
.global end
.arm
.section .text, "ax"
Reset_Handler:
/*
* Setup a stack for each mode
*/
msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */
ldr sp, =__stack_und_end__
msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */
ldr sp, =__stack_abt_end__
msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */
ldr sp, =__stack_fiq_end__
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */
ldr sp, =__stack_irq_end__
msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */
ldr sp, =__stack_svc_end__
/*
* Now enter crt0 function,
* which does low-level and segment initialization.
* and then calls main().
*/
ldr r0, =crt0
mov lr, pc
bx r0
end: b end
.end
Скрипт компоновщика
ENTRY(__vector)
/*********************************************************************
*
* Define stack sizes here
*/
FIQ_STACK_SIZE = 0x0;
IRQ_STACK_SIZE = 0x1000;
ABT_STACK_SIZE = 0x0;
UND_STACK_SIZE = 0x0;
SVC_STACK_SIZE = 0x1000;
MEMORY
{
RAM (wx) : ORIGIN = 0x200000, LENGTH = 0x8000
FLASH (rx) : ORIGIN = 0x100000, LENGTH = 0x10000
}
SECTIONS
{
.text :
{
*(.vectors);
. = ALIGN(8);
*(.init);
. = ALIGN(8);
*(.text);
. = ALIGN(8);
*(.rodata);
. = ALIGN(8);
*(.rodata*);
. = ALIGN(8);
*(.glue_7t);
. = ALIGN(8);
*(.glue_7);
. = ALIGN(8);
etext = .;
} > FLASH
. = ALIGN(8);
_etext = . ;
PROVIDE (etext = .);
.data : AT (_etext)
{
PROVIDE (__data_start__ = .);
_data = . ;
*(.data)
. = ALIGN(8);
PROVIDE (__data_end__ = .);
} > RAM
. = ALIGN(8);
_edata = . ;
PROVIDE (edata = .);
.bss :
{
PROVIDE (__bss_start__ = .);
*(.bss)
*(COMMON)
. = ALIGN(8);
PROVIDE (__bss_end__ = .);
. = ALIGN(256);
PROVIDE (__stack_start__ = .);
PROVIDE (__stack_fiq_start__ = .);
. += FIQ_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_fiq_end__ = .);
PROVIDE (__stack_irq_start__ = .);
. += IRQ_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_irq_end__ = .);
PROVIDE (__stack_abt_start__ = .);
. += ABT_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_abt_end__ = .);
PROVIDE (__stack_und_start__ = .);
. += UND_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_und_end__ = .);
PROVIDE (__stack_svc_start__ = .);
PROVIDE (__stack_svc_end__ = .);
PROVIDE (__stack_end__ = .);
PROVIDE (__heap_start__ = .);
. += 0x1000;
. = ALIGN(8);
PROVIDE (__heap_end__ = .);
} > RAM
}
ОБНОВЛЕНИЕ 2 Мои быстрые и грязные повторные воплощения системных вызовов.
int _write(int fd, char* buf, int len){
LED_On(1);
while(*buf){
UART_PutChar(*buf++);
}
return len;
}
void _ttywrch(int ch) {
LED_On(1);
UART_PutChar(ch);
}
signed int
putchar(signed int c)
{
return fputc(c, stdout);
}
signed int
fputs(const char* pStr, FILE* pStream)
{
signed int num = 0;
while (*pStr != 0)
{
if (fputc(*pStr, pStream) == -1)
{
return -1;
}
num++;
pStr++;
}
return num;
}
int
fputc(int c, FILE* pStream)
{
if ((pStream == stdout) || (pStream == stderr))
{
#ifdef UART_CONSOLE_CRLF
if (c == '\n')
UART_PutChar('\r');
#endif
UART_PutChar(c);
return c;
}
else
{
return EOF;
}
}
2 ответа
Ваша подпись putchar()
реализация очень сломана. Эти системные вызовы предназначены для процедур ввода-вывода самого низкого уровня, используемых библиотеками более высокого уровня, такими как stdio. Вы не можете реализовать их с помощью stdio! Вы без сомнения вызвали рекурсивный вызов, который ничего не будет выводить, а также быстро переполнит стек - после этого может произойти что угодно, но ничего хорошего.
int putchar( signed int c )
{
UART_PutChar( c ) ;
}
Ваш _write()
реализация также небезопасна и семантически неверна. Предполагается, что buf
строка с нулевым окончанием, которая никогда не должна иметь место - вы должны использовать len
Аргумент для вывода именно того, что запрашивает вызывающий:
int _write( int fd, char* buf, int len )
{
fd = fd ;
for( int i = 0; i < len; i++ )
{
UART_PutChar( buf[i] );
}
return i ;
}
Причина того, что _write()
никогда не называется, потому что вы обошли его путем переопределения fputs()
а также fputc()
- переопределение реализаций newlib, которые зависят только от системных вызовов.
Вы должны понимать, что эти подпрограммы являются основой, на которую опирается библиотека для правильной работы - "быстрая и грязная" недостаточно хороша; Безопасный, простой и семантически точный - это то, к чему вы должны стремиться.
printf()
для этого типа встроенной системы обычно требуется достаточное количество поддержки. В частности, должен быть _write()
Функция реализована, но ваш успешный вывод простых строк предполагает, что существует и работает.
Скорее, ваша проблема выглядит так, как будто она возникает в ситуациях, когда printf() необходимо выделить память. Через длинную цепочку зависимостей это может в конечном итоге пройти простой malloc() и в конечном итоге вызвать ваши реализации
void *_sbrk(int increment)
увеличить размер кучи. Если у вас нет реализации этого, или если она выходит из строя или сталкивается с другими областями, это может легко объяснить, почему ваша ошибка происходит только на выходах, которые требуют некоторого объединения для генерации.