[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-libc-dev] Re: snprintf bug ?
From: |
Russell Strong |
Subject: |
Re: [avr-libc-dev] Re: snprintf bug ? |
Date: |
Thu, 13 Oct 2005 20:46:25 +1000 |
Hi,
The following is the full source and Makefile for my snprintf bug
/****************************************************************
* *
* Dasboot Navigation Module *
* *
* Russell Strong <address@hidden> 21/9/2005 *
* *
* Designed for ATmega128. *
* FUSE settings for Jed Micro 570v1 module with 16Mhz crystal *
* *
* Fuse Low Byte = 0xff *
* Fuse High Byte = 0x9f *
* Fuse Extended Byte = 0xfe *
* Calibration Byte = 0xb2 -- Read Only *
* Lock Bits = 0xff *
* BLB12 -> 1 *
* BLB11 -> 1 *
* BLB02 -> 1 *
* BLB01 -> 1 *
* LB2 -> 1 *
* LB1 -> 1 *
* *
****************************************************************/
#define F_CPU 16000000UL
#include <avr/io.h>
#include <inttypes.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/wdt.h>
#define BUFFER_SIZE 100
#define MODULE_ID "05"
#define MODULE_NAME_CMD "("MODULE_ID"0)"
#define MODULE_VERSION_CMD "("MODULE_ID"1)"
#define HEADING_CMD "("MODULE_ID"2)"
#define GPGGA_CMD "("MODULE_ID"3)"
#define GPGSV1_CMD "("MODULE_ID"4)"
#define GPGSV2_CMD "("MODULE_ID"5)"
#define GPGSV3_CMD "("MODULE_ID"6)"
#define GPVTG_CMD "("MODULE_ID"7)"
#define PGRME_CMD "("MODULE_ID"8)"
#define PGRMT_CMD "("MODULE_ID"9)"
#define MODULE_NAME "NAV MODULE\r"
#define MODULE_VERSION "M05 V1\r"
static unsigned char gps_buff_next = 0;
static char gps_buff[BUFFER_SIZE];
static unsigned char gps_timeout_count = 0;
static char gpgga [BUFFER_SIZE] = "\r";
static char gpgsv1 [BUFFER_SIZE] = "\r";
static char gpgsv2 [BUFFER_SIZE] = "\r";
static char gpgsv3 [BUFFER_SIZE] = "\r";
static char gpvtg [BUFFER_SIZE] = "\r";
static char pgrme [BUFFER_SIZE] = "\r";
static char pgrmt [BUFFER_SIZE] = "\r";
static char heading [BUFFER_SIZE] = "\r";
static unsigned char bus_buff_next = 0;
static char bus_buff[BUFFER_SIZE];
static unsigned char bus_resp_buff_next = 0;
static char bus_resp_buff[BUFFER_SIZE];
void setup_hardware (void) __attribute__ ((naked)) __attribute__
((section (".init1")));
void setup_hardware (void)
{
_wdt_write (WDTO_2S); // Enabled via the fuses, i.e. don't need to
enable here.
// Just set the period to 2 seconds.
PORTA = 0xFE; // pullups on, outputs low.
DDRA = 0x01; // bit 0 = bus drivers
PORTB = 0xFF; // pullups on
PORTC = 0xFF; // pullups on
PORTD = 0xFF; // pullups on
PORTE = 0xFF; // pullups on
PORTF = 0xFF; // pullups on
PORTG = 0x1F; // pullups on
}
/******************************************************************
* *
* GPS COMMUNICATIONS *
* *
******************************************************************/
static void test_gps_timeout (void)
{
if (gps_timeout_count++ == 50) {
cli();
gpgga[0] = '\r';
gpgga[1] = '\0';
gpgsv1[0] = '\r';
gpgsv1[1] = '\0';
gpgsv2[0] = '\r';
gpgsv2[1] = '\0';
gpgsv3[0] = '\r';
gpgsv3[1] = '\0';
gpvtg[0] = '\r';
gpvtg[1] = '\0';
pgrme[0] = '\r';
pgrme[1] = '\0';
pgrmt[0] = '\r';
pgrmt[1] = '\0';
sei();
}
}
static void process_gps_message (void)
{
// GPGGA
if (gps_buff[4]=='G' && gps_buff[5]=='A') {
strcpy (gpgga, gps_buff+7);
return;
}
// GPGSV
if (gps_buff[4]=='S' && gps_buff[5]=='V') {
unsigned char comma_count=0, i=0;
while (comma_count < 2) {
if ((gps_buff[i] == '\0') || (i == BUFFER_SIZE-1))
return;
if (gps_buff[i] == ',')
comma_count++;
i++;
}
switch (gps_buff[i]) {
case '1':
strcpy (gpgsv1, gps_buff+7);
break;
case '2':
strcpy (gpgsv2, gps_buff+7);
break;
case '3':
strcpy (gpgsv3, gps_buff+7);
break;
default:
break;
}
return;
}
// GPVTG
if (gps_buff[4]=='T' && gps_buff[5]=='G') {
strcpy (gpvtg, gps_buff+7);
return;
}
// PGRME
if (gps_buff[4]=='M' && gps_buff[5]=='E') {
strcpy (pgrme, gps_buff+7);
return;
}
// PGRMT
if (gps_buff[4]=='M' && gps_buff[5]=='T')
strcpy (pgrmt, gps_buff+7);
}
SIGNAL (SIG_USART0_RECV)
{
char c = UDR0;
gps_timeout_count = 0;
if (c == '$') {
gps_buff[0] = c;
gps_buff_next = 1;
return;
}
if (gps_buff_next == BUFFER_SIZE-2) {
gps_buff_next = 0;
return;
}
gps_buff[gps_buff_next++] = c;
if (c == '*') {
gps_buff[gps_buff_next++] = '\r';
gps_buff[gps_buff_next] = '\0';
process_gps_message ();
gps_buff_next = 0;
}
}
/******************************************************************
* *
* DASBOOT BUS COMMUNICATIONS *
* *
******************************************************************/
static inline void start_bus_transmit (void)
{
if (bus_resp_buff[0] != '\0') {
PORTA |= _BV(0);
bus_resp_buff_next = 1;
UDR1 = bus_resp_buff[0];
UCSR1B |= _BV(UDRIE1);
}
}
static inline void process_bus_message ()
{
if (strcmp(bus_buff, HEADING_CMD) == 0) {
strcpy(bus_resp_buff, heading);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, GPGGA_CMD) == 0) {
strcpy(bus_resp_buff, gpgga);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, GPVTG_CMD) == 0) {
strcpy(bus_resp_buff, gpvtg);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, PGRME_CMD) == 0) {
strcpy(bus_resp_buff, pgrme);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, GPGSV1_CMD) == 0) {
strcpy(bus_resp_buff, gpgsv1);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, GPGSV2_CMD) == 0) {
strcpy(bus_resp_buff, gpgsv2);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, GPGSV3_CMD) == 0) {
strcpy(bus_resp_buff, gpgsv3);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, PGRMT_CMD) == 0) {
strcpy(bus_resp_buff, pgrmt);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, MODULE_NAME_CMD) == 0) {
strcpy(bus_resp_buff, MODULE_NAME);
start_bus_transmit();
return;
}
if (strcmp(bus_buff, MODULE_VERSION_CMD) == 0) {
strcpy(bus_resp_buff, MODULE_VERSION);
start_bus_transmit();
return;
}
}
SIGNAL (SIG_USART1_RECV)
{
char c = UDR1;
if (c == '(') {
bus_buff[0] = c;
bus_buff_next = 1;
return;
}
if (bus_buff_next == BUFFER_SIZE-1) {
bus_buff_next = 0;
return;
}
bus_buff[bus_buff_next++] = c;
if (c == ')') {
bus_buff[bus_buff_next] = '\0';
process_bus_message ();
bus_buff_next = 0;
}
}
SIGNAL (SIG_USART1_DATA)
{
char c = bus_resp_buff[bus_resp_buff_next++];
if (c == '\0')
UCSR1B &= ~_BV(UDRIE1);
else
UDR1 = c;
}
SIGNAL (SIG_USART1_TRANS)
{
if (!(UCSR1B & _BV(UDRIE1)))
PORTA &= ~_BV(0);
}
/******************************************************************
* *
* COMPASS COMMUNICATIONS (mostly) *
* *
******************************************************************/
#define HDG_CNT 60
static int headings[HDG_CNT] = {0};
static void insert_heading (hdg)
{
static unsigned char next = 0;
headings[next] = hdg;
next = (next + 1) % HDG_CNT;
}
static int delta_heading (hdg, base_hdg)
{
int cw, ccw;
cw = hdg - base_hdg;
if (cw < 0)
cw += 3600;
ccw = base_hdg - hdg;
if (ccw < 0)
ccw += 3600;
if (cw < ccw)
return cw;
else
return -ccw;
}
static void update_heading_string (int hdg_reading)
{
long delta = 0;
unsigned char i;
static int base_hdg = 0;
// static char heading_tmp[5]; // This works
char heading_tmp[5]; // This doesn't work
insert_heading (hdg_reading);
for (i=0;i<HDG_CNT;i++)
delta += delta_heading (headings[i], base_hdg);
base_hdg += delta / HDG_CNT;
if (base_hdg >= 3600)
base_hdg -= 3600;
else if (base_hdg < 0)
base_hdg += 3600;
snprintf (heading_tmp, 5, "%04X", base_hdg);
// store heading ready for bus transmission
cli();
heading[0] = heading_tmp[0];
heading[1] = heading_tmp[1];
heading[2] = heading_tmp[2];
heading[3] = heading_tmp[3];
heading[4] = '\r';
heading[5] = '\0';
sei();
}
int main () __attribute__ ((naked));
int main ()
{
// For some reason, initiallizing USART 1 in section .init1
// causes the USART to have the wrong baud rate after a power on reset.
// However resetting using the reset switch, would install the correct
// settings. It would appear that USART1 takes longer than the rest of
// the MCU to become stable after power is applied. This is why
// peripheral initiallisation has been moved to the main function.
// PIN directions and initial values are still done in section .init1
// And I did tried this on multiple MCUs.
// USART 0 GPS Interface
UBRR0H = 0x01; // 4800 8N1 ( actual 4808 bps )
UBRR0L = 0x9F;
UCSR0A = _BV(UDRE0) | _BV(U2X0);
UCSR0B = _BV(RXEN0) | _BV(RXCIE0);
// USART 1 DASBOOT BUS Interface
UBRR1H = 0x00; // 57600 8N1 ( actual 57142 bps )
UBRR1L = 0x22;
UCSR1A = _BV(UDRE1) | _BV(U2X1);
UCSR1B = _BV(RXEN1) | _BV(TXEN1) | _BV(RXCIE1) | _BV(TXCIE1);
// Compass TWI Interface
TWSR |= _BV(TWPS0); // TWI Prescaler ( / 4 )
TWBR = 0x26; // TWI Bit Rate ( 50000 bps )
sei ();
for(;;) {
unsigned char heading_byte_1, heading_byte_2;
wdt_reset ();
_delay_ms (100.0); // FIXME - not behaving as expected ? check
on CRO
// Test for GPS timeout
test_gps_timeout ();
// Send start condition
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that the START
// condition has been transmitted.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI Status Register. Mask Prescalar bits.
// If status different from START goto error.
if ((TWSR & 0xF8) != 0x08) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Load SLA_W into TWDR register. Clear TWINT bit in TWCR
// to start transmission of address
// 0xC0 is address with write bit of CMPS03
TWDR = 0xC0;
TWCR = _BV(TWINT) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that the SLA_W
// has been transmitted, and ACK/NACK has been received.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI status register. Mask prescalar bits.
// If status different from MT_SLA_ACK goto error.
if ((TWSR & 0xF8) != 0x18) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Load DATA into TWDR register. Clear TWINT bit in TWCR to
// start transmission of data.
// Send 0x02 to CMPS03 to read register 2,3.
TWDR = 0x02;
TWCR = _BV(TWINT) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that the DATA has
// been transmitted, and ACK/NACK has been recieved
while (!(TWCR & _BV(TWINT)));
// Check value of TWI status register. Mask prescalar bits.
// If status different from MT_DATA_ACK goto error.
if ((TWSR & 0xF8) != 0x28) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Send repeated start condition.
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that the REPEATED
// START condition has been transmitted.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI Status Register. Mask Prescalar bits.
// If status different from REPEATED START goto error.
if ((TWSR & 0xF8) != 0x10) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Load SLA_R into TWDR register. Clear TWINT bit in TWCR
// to start transmission of address
// 0xC1 is address with read bit of CMPS03
TWDR = 0xC1;
TWCR = _BV(TWINT) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that the SLA_R
// has been transmitted.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI Status Register. Mask Prescalar bits.
// If status different from MT_SLA_R_ACK goto error.
if ((TWSR & 0xF8) != 0x40) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Clear TWINT bit in TWCR to start receiving the first data
// byte. Set TWEA to generate an ack condition when byte
received.
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
// Wait for TWINT flag set. This indicates that DATA
// has been recieved and ACK or NACK is set.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI Status Register. Mask Prescalar bits.
// If status different from DATA byte recieved with ACK then
// goto error.
if ((TWSR & 0xF8) != 0x50) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Save the first data byte
heading_byte_1 = TWDR;
// Clear TWINT bit in TWCR to start receiving the second data
// byte. Set TWEA to generate a NAK condition when byte
received.
TWCR = _BV(TWINT) | _BV(TWEN);
// Wait for TWINT flag set. This indicates that DATA
// has been recieved and ACK or NACK is set.
while (!(TWCR & _BV(TWINT)));
// Check value of TWI Status Register. Mask Prescalar bits.
// If status different from DATA byte recieved with NAK then
// goto error.
if ((TWSR & 0xF8) != 0x58) {
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
continue;
}
// Save the second data byte
heading_byte_2 = TWDR;
// Stop condition
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
// update heading for bus tranmission
update_heading_string (heading_byte_1 * 256 + heading_byte_2);
}
}
PRG =navigation
OBJ =navigation.o
MCU_TARGET = atmega128
OPTIMIZE = -O2
DEFS =
LIBS =
# You should not have to change anything below here.
CC = avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS = -Wl,-Map,$(PRG).map
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: $(PRG).elf lst text eeprom
$(PRG).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak
rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)
lst: $(PRG).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
# Rules for building the .text rom images
text: hex bin srec
hex: $(PRG).hex
bin: $(PRG).bin
srec: $(PRG).srec
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@
# Rules for building the .eeprom rom images
eeprom: ehex ebin esrec
ehex: $(PRG)_eeprom.hex
ebin: $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec
%_eeprom.hex: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
%_eeprom.srec: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@
%_eeprom.bin: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@
# Every thing below here is used by avr-libc's build system and can be
ignored
# by the casual user.
FIG2DEV = fig2dev
EXTRA_CLEAN_FILES = *.hex *.bin *.srec
dox: eps png pdf
eps: $(PRG).eps
png: $(PRG).png
pdf: $(PRG).pdf
%.eps: %.fig
$(FIG2DEV) -L eps $< $@
%.pdf: %.fig
$(FIG2DEV) -L pdf $< $@
%.png: %.fig
$(FIG2DEV) -L png $< $@
On Thu, 2005-10-13 at 09:53 +0200, Joerg Wunsch wrote:
> As Russell Strong wrote:
>
> > Am I doing something illegal? Do snprintf pointers need to be
> > static?
>
> No, and no.
>
> Can you provide a full, compilable example that demonstrates the
> problem?
>
signature.asc
Description: This is a digitally signed message part
- [avr-libc-dev] snprintf bug ?, Russell Strong, 2005/10/13
- [avr-libc-dev] Re: snprintf bug ?, Joerg Wunsch, 2005/10/13
- Re: [avr-libc-dev] Re: snprintf bug ?,
Russell Strong <=
- Re: [avr-libc-dev] Re: snprintf bug ?, Dmitry K., 2005/10/13
- Re: [avr-libc-dev] Re: snprintf bug ?, Björn Haase, 2005/10/14
- Re: [avr-libc-dev] Re: snprintf bug ?, Marek Michalkiewicz, 2005/10/14
- RE: [avr-libc-dev] Re: snprintf bug ?, Darcy Watkins, 2005/10/14
- Re: [avr-libc-dev] Re: snprintf bug ?, Joerg Wunsch, 2005/10/15
- Re: [avr-libc-dev] Re: snprintf bug ?, Joerg Wunsch, 2005/10/14
- Re: [avr-libc-dev] Re: snprintf bug ?, Russell Strong, 2005/10/14
Re: [avr-libc-dev] snprintf bug ?, Bernard Fouché, 2005/10/13