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)

увеличить размер кучи. Если у вас нет реализации этого, или если она выходит из строя или сталкивается с другими областями, это может легко объяснить, почему ваша ошибка происходит только на выходах, которые требуют некоторого объединения для генерации.

Другие вопросы по тегам