2014-10-10 2 views
3

Я пишу программу для запуска на ATmega328p - голый avr-libc, а не Arduino, хотя он использует загрузчик Arduino по серийному номеру (я не думаю, что это затрагивает следующий вопрос хоть).fprintf() на avr-libc мгновенно вылетает

Я создал stdout написать УАППЫ в, надеюсь, очевидным образом:

void uart_putc(char c) 
{ 
    // Turn LFs into CRLFs 
    if(c == '\n') 
    uart_putc('\r'); 

    while(!(UCSR0A & _BV(UDRE0))) 
    ; 

    UDR0 = c; 
} 

static int _putc(char c, FILE *_) 
{ 
    uart_putc(c); 
    return 0; 
} 

... 
    fdev_setup_stream(stdout, &_putc, NULL, _FDEV_SETUP_WRITE); 

Если я сейчас пишу свою программу, используя только fputc и fputs то все работает отлично. Я могу даже позвонить snprintf(), чтобы отформатировать форматированные строки в char buffer[16], а затем fputs() их; все это прекрасно работает.

fputs("Hello, world\n", stdout); /* works fine */ 

char buffer[16]; 
snprintf(buffer, sizeof buffer, "Hello, %s\n", "world"); 
fputs(buffer, stdout);    /* also works fine */ 

Однако, в тот момент я пытаюсь выполнить реальные fprintf() на stdout сбои программы и перезагружает ATMEGA:

fprintf(stdout, "Hello, %s\n", "world"); 

Он выходит из строя сразу, еще до выдачи первоначального H здесь.

Может ли кто-нибудь предложить что-то, что может отсутствовать, что остановит работу fprintf(), когда оба snprintf() и fputs() могут нормально работать?

+0

Возможно, вы увидите, есть ли симулятор с отладчиком, на котором вы могли бы запустить его. –

+1

Шаг в 'fprintf' и« прогуляйтесь »по разборке до сбоя. Затем сделайте это еще раз и перед выполнением инструкции, которая вызывает сбой, откройте регистр, просмотрите все регистры и опубликуйте их здесь. Кроме того, опубликуйте инструкцию, которая вызывает сбой. Это может предоставить нам значительную часть информации. Кстати, вы можете сделать то же самое с 'fputs' и сами убедиться, как работает, а другой не работает. –

+0

Авария, связанная с любой функцией printf, заставляет меня думать о переполнении стека. Попробуйте увеличить размер стека. – kkrambo

ответ

0

Вы используете fdev_setup_stream(), чтобы уточнить назначение stdout. documentation of fdev_setup_stream() явно заявляет, хотя:

Примечание: Нет присвоений стандартных потоков будет выполняться fdev_setup_stream(). Если стандартные потоки должны использоваться, они должны быть назначены пользователем.

Этот же документ указывает на code example for using stdio without malloc. код там выглядит очень похоже на твое за исключением двух вещей:

  1. Произвольный поток определяют с помощью макроса FDEV_SETUP_STREAM():

    static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); 
    
  2. stdout инициализируется этого пользовательского потока:

    stdout = &mystdout; 
    

Я думаю, ваша треска e использует неинициализированный поток stdout. "Введение в объекты Standard IO" (www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#details) гласит:

стандартных потоков STDIN, STDOUT и STDERR предоставляются, но вопреки стандарту C, поскольку avr-libc не знает о применимых устройствах, эти потоки уже не инициализируются при запуске приложения.

При отсутствии инициализации поведение всех вызовов функций с использованием stdout не определено.В зависимости от того, где на самом деле указывает stdout, некоторые вызовы могут работать.