尝试打印到UART时ARM7 printf挂起

时间:2016-06-01 16:13:20

标签: gcc embedded bare-metal newlib arm7

我遇到各种打印命令的问题 每当我试图调用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("\n");时,

printf将起作用 如果我执行类似

的操作,printf将只打印换行符
fputc('B', stdin); //notice stdin
printf("test\n"); //prints newline

在某些情况下,当fprintf失败时,它将返回EOF(现在不能记住它们,如果相关则会明天提供它们)
(f)printf似乎在调用putchar,我已将其重新定位到UART 奇怪的是我认为应该调用newlib-nano提供的_write_write_r例程(而printf不会调用它们)。
作为IDE我正在使用EmBitz和它提供的工具链(arm-none-eabi)。我正在使用的CPU是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 个答案:

答案 0 :(得分:1)

您签名的putchar()实施非常糟糕。这些系统调用旨在成为更高级别库(如stdio)使用的最低级别I / O例程。你无法使用 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实现系统调用。

你必须意识到这些例程是图书馆依赖于正常工作的基础 - “快速和肮脏”不够好;安全,简单和语义精确是你应该瞄准的目标。

答案 1 :(得分:0)

此类嵌入式系统上的

printf()通常需要相当多的支持。特别是,需要实现_write()函数,但是您成功输出的简单字符串表明存在并且有效。

相反,您的问题看起来可能是在printf()需要分配内存的情况下出现的。通过一长串依赖关系,这最终可以通过一个简单的malloc()并最终调用您的

实现
void *_sbrk(int increment)

增加堆大小。如果您没有这样的实现,或者它失败或与其他区域发生冲突,它可以很容易地解释为什么您的故障仅发生在需要一起拼接生成的输出上。