PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Controller startet bei atol neu?



Tux12Fun
06.04.2020, 21:36
Hallo,

vielleicht kann mir jemand helfen. Ich bin echt am verzweifeln.
Ich habe ein bisschen C Programmiert und bin auf ein Problem gestoßen.
Ich weiß echt nicht mehr weiter und finde einfach den Fehler nicht.

Sobald ich in der Funktion get_BTData(char mode) eine atoi/atol oder scanf Funktion einbaue,
löst der ATMEGA8 bei USART_Init(9600); einen reboot aus.

Das sehe ich daran, dass mein Programm folgendes verhalten zeigt.

OHNE ATOL
==========
LED blinkt grün 2x
LED blinkt blau 2x
LED geht aus und leuchtet dann durch gehend blau.

-- Der ATMEGA wartet auf Kommandos vom BT Module


Jetzt ändere ich nur eine Zeile (143 in der main.c) pl_valid_time_sec = atol(spl_buffer);
===========================
LED blinkt grün 2x
LED blinkt blau 2x
LED blinkt grün 2x
LED blinkt blau 2x
LED blinkt grün 2x
LED blinkt blau 2x
....


Ich versteh die Welt nicht mehr, baue ich die atol Zeile wieder aus, geht es wieder.
Ich habe auch schon an eine Compiler Optimierung oder einen Speicher Überlauf gedacht.
Aber müsste da nicht gcc eine Warnung ausgeben.

Es gab auch keine Änderung wenn ich zwischen -os oder -o2 wechsel. ( avr-gcc (Gentoo 8.3.0-r1 p1.1) 8.3.0)

Vielleicht habt ihr noch eine Idee der ATMEGA8A läuft bei 2Mhz das BT Module ist ein HC-05

main.c


#define MCU atmega8
#define F_CPU 2000000UL
//-U lfuse:w:0xe2:m -U hfuse:w:0xd9:m
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>

#include <stdlib.h>
#include <stdio.h>

#include <avr/eeprom.h>
#define EEPROM_DEF 0xFF

#include "USART_RS232_H_file.h" /* include USART library */

#define UART_IN_BUFFER_LEN 512

#define BT_EN_REGISTER DDRC
#define BT_EN_PORT PORTC
#define BT_EN_PIN PC0


#define LED_REGISTER DDRC
#define LED_PORT PORTC
#define LED_RED_PIN PC5
#define LED_GREEN_PIN PC4
#define LED_BLUE_PIN PC3

uint8_t gEi_initCode EEMEM = 123;

long gl_remaining_time = 15;
char gc_intrusion_detected = 0;
char gi_wakeup_pressed =0;
char* gs_verificationCode = "ddd";

//Data from App
char pc_code_sement[UART_IN_BUFFER_LEN];
long pl_valid_time_sec = 0;
long pl_lock_time_sec = 0;
int pi_multiplikator = 0;


char bitRead(char *x, char n) {
return (*x & (1 << n)) ? 1 : 0;
}


void my_sleep(uint16_t sec){
for (unsigned short int i =0; i < sec; i++){
_delay_ms(1000);
}
}

uint8_t uart_getc(uint8_t timeout){
uint32_t i_timeout = timeout;
uint32_t runntime = 0;
while (!(UCSRA & (1<<RXC))){ // warten bis Zeichen verfuegbar
runntime++;
if (runntime >= F_CPU){
runntime=0;
i_timeout--;
if (i_timeout == 0){
return '\0';
}
}
}
return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben
}

void uart_gets( char* Buffer, uint32_t MaxLen, uint32_t timeout ){
uint8_t NextChar;
uint32_t StringLen = 0;
NextChar = uart_getc(timeout); // Warte auf und empfange das nächste Zeichen
while( NextChar != '\n' && StringLen < MaxLen - 1 ) { // Sammle solange Zeichen, bis: entweder das String Ende Zeichen kam oder das aufnehmende Array voll ist
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc(timeout);

}
*Buffer = '\0'; // Noch ein '\0' anhängen um einen Standard C-String daraus zu machen
}


long getCurrentVoltage(void){
long adc_result = 0; //Gesamtergebnis der Messung des ADC
ADMUX |= (1<<REFS0) | (1<<REFS1) ; //VCC als Referenzspannung für den AD-Wandler
ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1); //1.3V Referenzspannung als Eingang für ADC
_delay_ms(2000); //warten bis sich die Referenzspannung eingestellt hat
ADCSRA |= (1<<ADEN); //ADC aktivieren
for (int i=0; i < 11; i++){
ADCSRA |= (1<<ADSC); //Messung starten
while(!(ADCSRA&(1<<ADIF))){
//warten bis Messung beendet ist
}
//Ergebnisse des ADC zwischenspeichern. Wichtig: zuerst ADCL auslesen, dann ADCH
if (i != 0){ adc_result = adc_result + ADCW; }
ADCSRA |= (1<<ADIF); //Bit Freigeben
}
return adc_result;
}



void get_BTData(char mode){
char uart_buffer[UART_IN_BUFFER_LEN];
// Enable Power for Bluetooth
BT_EN_PORT &= ~(1<<BT_EN_PIN);

for(int i=0; i<4; i++){
LED_PORT ^= (1 << LED_BLUE_PIN);
_delay_ms(500);
}

USART_Init(9600); /* initialize USART with 9600 baud rate */
LED_PORT |= (1<<LED_BLUE_PIN);

uart_gets(uart_buffer,UART_IN_BUFFER_LEN,60);
if (uart_buffer[0] == '\0'){ // TIMEOUT
}else if ( (mode=='I') && (uart_buffer[0] == 'I') && (uart_buffer[1] == 'N') && (uart_buffer[2] == 'I') && (uart_buffer[3] == 'T') && (uart_buffer[4] == ':') ){ // INIT CODE
gEi_initCode = atoi(uart_buffer+5);
eeprom_write_byte(&gEi_initCode, gEi_initCode); // schreiben
USART_SendString("KSR_IC:InitCode Saved"); // KeySaveResponse_InformationCode

}else if ( (mode=='I') && (uart_buffer[0] == 'S') && (uart_buffer[1] == 'E') && (uart_buffer[2] == 'T') && (uart_buffer[3] == 'K') && (uart_buffer[4] == ':') ){ // SET KeySafe Code
//Read Init Code from EEPROM
gEi_initCode = eeprom_read_byte(&gEi_initCode);

char spl_buffer[UART_IN_BUFFER_LEN];
uint8_t ele = 0;
// Split up
uint32_t ii=0;
for (uint32_t i=5; i < UART_IN_BUFFER_LEN; i++){
pc_code_sement[i-5] = uart_buffer[i]; //Copy Code
spl_buffer[ii] = uart_buffer[i];

if ((ele == 0) && (uart_buffer[i] == ',')){
spl_buffer[ii] = '\0';
//pl_valid_time_sec = atol(spl_buffer);
ele++;
ii=0;
}else if ((ele == 1) && (uart_buffer[i] == ',')){
spl_buffer[ii] = '\0';
//pl_lock_time_sec = atol(spl_buffer);
ele++;
ii=0;
}else if ((ele == 2) && (uart_buffer[i] == ',')){
spl_buffer[ii] = '\0';
//pi_multiplikator=atoi(spl_buffer);
ele++;
ii=0;
break;
}
ii++;
}

snprintf(uart_buffer, sizeof uart_buffer, "KSR_RT:%ld\nKSR_ES:%ld\nKSR_ID:%s\n", gl_remaining_time,getCurrentVoltage(),gs_verificat ionCode);
USART_SendString(uart_buffer);
}else if ( (uart_buffer[0] == 'G') && (uart_buffer[1] == 'E') && (uart_buffer[2] == 'T') && (uart_buffer[3] == 'S') && (uart_buffer[4] == ':') ){ // GET Status
snprintf(uart_buffer, sizeof uart_buffer, "KSR_RT:%ld\nKSR_ES:%ld\nKSR_ID:%s\n", gl_remaining_time,getCurrentVoltage(),gs_verificat ionCode); /
USART_SendString(uart_buffer);
}else{
USART_SendString("KSR_EC:UnknwonCommand");
}
_delay_ms(5000);
LED_PORT &= ~(1<<LED_BLUE_PIN);
BT_EN_PORT |= (1<<BT_EN_PIN);
}



int main(void){
// Save Power
ACSR = 0x80; // Disable Analogcomparator
ADCSRA = 0; // Disable ADC

// Direction Registers
DDRB = 0x00; // B as input
DDRC = 0x00; // D as Input
DDRD = 0x00; // D as Input

// Set Output Registers
BT_EN_REGISTER |= (1 << BT_EN_PIN); // Bluetooth PWR Controll
LED_REGISTER |= (1 << LED_RED_PIN); // LED as output
LED_REGISTER |= (1 << LED_GREEN_PIN); // LED as output
LED_REGISTER |= (1 << LED_BLUE_PIN); // LED as output

// Ports to LOW (GND no Pullup)
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);

get_BTData('I'); // INIT MODE


while(1){
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
}

}


Eingebunden ist noch die
* USART_RS232_C_file.c
https://www.electronicwings.com/users/amrutu/codes/hc05_bluetooth_interface_with_atmega

HaWe
06.04.2020, 22:09
kürze dein Programm doch bitte mal auf die minimalste Version zurück, in der sich der Fehler gerade noch zeigen lässt - alles andere an Codezeilen löschen.

Tux12Fun
06.04.2020, 22:44
Hallo HaWe,

ich habe mich gleich ans Werk gemacht und den Code gekürzt das verhalten ist noch 1:1 das gleiche.
Schon mal vielen Dank, dass du dir den Quellcode an siehst und mir hilfst.



#define MCU atmega8
#define F_CPU 2000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "USART_RS232_H_file.h" /* include USART library */

#define BT_EN_REGISTER DDRC
#define BT_EN_PORT PORTC
#define BT_EN_PIN PC0

#define LED_REGISTER DDRC
#define LED_PORT PORTC
#define LED_RED_PIN PC5
#define LED_GREEN_PIN PC4
#define LED_BLUE_PIN PC3

//Data from App
long pl_valid_time_sec = 0;

uint8_t uart_getc(void){
while (!(UCSRA & (1<<RXC))){} // warten bis Zeichen verfuegbar
return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben
}

void uart_gets( char* Buffer, uint32_t MaxLen){
uint8_t NextChar;
uint32_t StringLen = 0;

NextChar = uart_getc(); // Warte auf und empfange das nächste Zeichen
while( NextChar != '\n' && StringLen < MaxLen - 1 ) { // Sammle solange Zeichen, bis: entweder das String Ende Zeichen kam oder das aufnehmende Array voll ist
*Buffer++ = NextChar;
StringLen++;
NextChar = uart_getc();
}
*Buffer = '\0'; // Noch ein '\0' anhängen um einen Standard C-String daraus zu machen
}


void get_BTData(char mode){
char uart_buffer[512];

for(int i=0; i<4; i++){
LED_PORT ^= (1 << LED_BLUE_PIN);
_delay_ms(500);
}

USART_Init(9600); /* initialize USART with 9600 baud rate */
LED_PORT |= (1<<LED_BLUE_PIN);

uart_gets(uart_buffer,512);

char spl_buffer[512];
spl_buffer[0] = '1'; spl_buffer[1] = '2'; spl_buffer[1] = '\0';
pl_valid_time_sec = atol(spl_buffer);

_delay_ms(5000);
LED_PORT &= ~(1<<LED_BLUE_PIN);
}

int main(void){
// Direction Registers
DDRB = 0x00; // B as input
DDRC = 0x00; // D as Input
DDRD = 0x00; // D as Input

// Set Output Registers
BT_EN_REGISTER |= (1 << BT_EN_PIN); // Bluetooth PWR Controll
LED_REGISTER |= (1 << LED_RED_PIN); // LED as output
LED_REGISTER |= (1 << LED_GREEN_PIN); // LED as output
LED_REGISTER |= (1 << LED_BLUE_PIN); // LED as output

// Ports to LOW (GND no Pullup)
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

for (int i=0; i < 4; i++){
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
}

get_BTData('I'); // INIT MODE

while(1){
LED_PORT ^= (1 << LED_RED_PIN);
_delay_ms(500);
}

}


Wenn ich wüsste was hier bei der Lib an BAUD steht, könnte ich die ganze Lib auch noch ausbauen
Der ATMEGA läuft bei 2Mhz


void USART_Init(unsigned long BAUDRATE) /* USART initialize function */
{
UCSRB |= (1 << RXEN) | (1 << TXEN); /* Enable USART transmitter and receiver */
UCSRC |= (1 << URSEL)| (1 << UCSZ0) | (1 << UCSZ1); /* Write USCRC for 8 bit data and 1 stop bit */
UBRRL = BAUD_PRESCALE; /* Load UBRRL with lower 8 bit of prescale value */
UBRRH = (BAUD_PRESCALE >> 8); /* Load UBRRH with upper 8 bit of prescale value */
}

HaWe
06.04.2020, 22:51
UART und LED-Code auch mal rauslöschen. wenn atol eine runtime-Exception auslöst, müsste es davon unabhängig sein.
Stattdessen könntest du Zeichen aus UART auch durch const cstrings testweise ersetzen.


On success, the function returns the converted integral number as a long int value.
If no valid conversion could be performed, a zero value is returned.
If the converted value would be out of the range of representable values by a long int, it causes undefined behavior. See strtol for a more robust cross-platform alternative when this is a possibility. http://www.cplusplus.com/reference/cstdlib/atol/

Tux12Fun
06.04.2020, 22:57
Ich habe jetzt

uint8_t uart_getc(void){
void uart_gets( char* Buffer, uint32_t MaxLen){

Auskommentiert und den Aufruf USART_Init(9600); uart_gets(uart_buffer,512);

jetzt bleibt die Blaue LED an. -> Also ok.

Die Led brauche ich damit ich mit bekomme was das Programm tut.


Wenn ich den Init wieder aktiviere geht es auch noch beim uart_gets(uart_buffer,512); habe ich wieder den Fehler.

HaWe
06.04.2020, 23:00
das deutet für mich darauf hin, dass der UART-buffer aus uart_getc() oder uart_gets() einen ungültigen Wert liefern könnte, der eine Exception auslöst. Ich verstehe hier aber deinen Code zugegebenermaßen nicht.
Kannst du diesen UART-Wert auslesen, anzeigen (Display?) und checken, bevor du ihn an atol übergibst?

Tux12Fun
06.04.2020, 23:05
Aber ich gebe ja atol inzwischen schon einen fixen String und nichts mehr aus den UART Buffer.

HaWe
06.04.2020, 23:19
also passiert der Fehler gar nicht in atol? Sondern in uart_getc() oder uart_gets() ? Oder wie oder was?

Tux12Fun
06.04.2020, 23:53
Genau das versuche ich gerade heraus zu finden.
Leider ist das ganze UART Thema für mich auch Neuland.

- - - Aktualisiert - - -

Ich hab schön langsam eine Ahnung, ich glaub ich hab mehr RAM verbraucht als der ATMEL hat und
sobald ich dann irgendwo im RAM schreibe wo ich nicht sein sollte macht es boom

Wenn ich nämlich wie jetzt hier den buffer auf 512 setze geht es noch bei 1024 gibt es undefiniertes verhalten.

Und das Datenblatt bestätigt das wohl gerade
– 1KByte Internal SRAM :( daran dachte ich wohl nicht.

Klingt das für euch Logisch?



#define MCU atmega8
#define F_CPU 2000000UL
//-U lfuse:w:0xe2:m -U hfuse:w:0xd9:m
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>

#define BT_EN_REGISTER DDRC
#define BT_EN_PORT PORTC
#define BT_EN_PIN PC0

#define LED_REGISTER DDRC
#define LED_PORT PORTC
#define LED_RED_PIN PC5
#define LED_GREEN_PIN PC4
#define LED_BLUE_PIN PC3

// BAUDRATE
#define BAUD_PRESCALE (((F_CPU / (9600 * 16UL))) - 1) /* Define prescale value */

//Data from App
long pl_valid_time_sec = 0;

void USART_SendString(char *str){
int i=0;
while (str[i]!=0){
UDR = str[i]; /* Write data to be transmitting in UDR */
while (!(UCSRA & (1<<UDRE))); /* Wait until data transmit and buffer get empty */
i++;
}
}

void get_BTData(){
// INIT USART
UCSRB |= (1 << RXEN) | (1 << TXEN); /* Enable USART transmitter and receiver */
UCSRC |= (1 << URSEL)| (1 << UCSZ0) | (1 << UCSZ1); /* Write USCRC for 8 bit data and 1 stop bit */
UBRRL = BAUD_PRESCALE; /* Load UBRRL with lower 8 bit of prescale value */
UBRRH = (BAUD_PRESCALE >> 8); /* Load UBRRH with upper 8 bit of prescale value */

LED_PORT |= (1<<LED_BLUE_PIN);

int i=0;
uint8_t c = '\0';
uint8_t uart_buffer[1024];

while( i < 512){
while (!(UCSRA & (1<<RXC))){}
c = UDR;
if ( c == '\n' ){ break; }
uart_buffer[i] = c;
i++;
}
uart_buffer[i]='\0';

USART_SendString("TEST");
USART_SendString(uart_buffer);


char spl_buffer[12];
spl_buffer[0] = '1'; spl_buffer[1] = '2'; spl_buffer[1] = '\0';
pl_valid_time_sec = atol(spl_buffer);

_delay_ms(5000);
LED_PORT &= ~(1<<LED_BLUE_PIN);
}

int main(void){
// Direction Registers
DDRB = 0x00; // B as input
DDRC = 0x00; // D as Input
DDRD = 0x00; // D as Input

// Set Output Registers
BT_EN_REGISTER |= (1 << BT_EN_PIN); // Bluetooth PWR Controll
LED_REGISTER |= (1 << LED_RED_PIN); // LED as output
LED_REGISTER |= (1 << LED_GREEN_PIN); // LED as output
LED_REGISTER |= (1 << LED_BLUE_PIN); // LED as output

// Ports to LOW (GND no Pullup)
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

for (int i=0; i < 4; i++){
LED_PORT ^= (1 << LED_GREEN_PIN);
_delay_ms(500);
}

get_BTData(); // INIT MODE

while(1){
LED_PORT ^= (1 << LED_RED_PIN);
_delay_ms(500);
}

}

Moppi
07.04.2020, 08:41
Morgen Tux,

Dein Buffer (uint8_t uart_buffer[1024];) befindet sich innerhalb "void get_BTData()".
Das Problem gab es hier schon in verschiedenen Fällen, dass so etwas dann Probleme bereitet (Stapelspeicher).
Eventuell bringts Dir was, "uint8_t uart_buffer[1024];" global anzulegen, also außerhalb jeder Funktion, das könnte das Problem beseitigen.


MfG

shedepe
07.04.2020, 09:05
Mal noch so als idee: Du hast da einen 1kB großen Buffer -> Das ist ganz schön viel für einen kleinen Atmega. Überleg dir doch mal ob du die Daten nicht. Stückchenweise oder sogar Interrupt basiert verarbeiten kannst.

Siro
07.04.2020, 10:37
Hallo Tux12Fun,

der ATMega8 hat nur 1 KByte RAM
Diesen Speicher teilen sich Stack und Daten.
Je mehr Speicher für den Stack angelegt wird, desto weniger bleibt also für den RAM übrig.

Es ist unmöglich einen Puffer mit 1024 Bytes anzulegen
und schon garnicht gleich zweie davon:

char uart_buffer[UART_IN_BUFFER_LEN];
char spl_buffer[UART_IN_BUFFER_LEN];

Normalerweise merkt das ein Compiler und gibt eine entsprechende Fehler oder Warnmeldung raus.
Da diese Arrays aber bei deinem Code lokal innerhalb der Funktion get_BTData(char mode) definiert sind,
ist es vermutlich für den Compiler nicht eindeutig, weil der Speicher ja nicht ständig,
sondern nur innerhalb der Funktion reserviert und auch wieder verworfen wird.

Ich würde testweise mal vorschlagen die Arrays ausserhalb der Funktion zu platzieren
und neu zu kompilieren. Meiner Meinung nach müsste es dann eine entsprechende Fehlermeldung geben.

Du brauchts auch eher unwahrschienlich diese riesiegen Puffer von 512 oder sogar 1024 Bytes.
Ich komme meistens mit 16 bis 32 Bytes für meine serielle Schnittstelle aus.

Das Verhalten der Software bei solch einem Problem ist völlig zufällig und da kann man sich wirklich nen Wolf suchen.
Wie HaWe auch gleich schrieb: Code auf das minimalste kürzen.
Deine Idee mit den verschiedenen Optimierungen des Compilers ist übrigens eine sehr gute Testmethode,
das mache ich auch oft bei unerklärlichem Verhalten. Der Code sollte aber immer mit allen Optimierungen laufen.
Zumindest ist das generell mein oberstes Gebot.

Siro

Tux12Fun
07.04.2020, 19:57
Vielen Dank,

genau das war auch das Problem, jetzt habe ich meine buffer schön kompakt auf 100 Byte begrenzt und bin total happy.

Danke für die ganze Unterstützung bei der Fehlersuche.

Nun habe ich noch ein kleines Timer Problem. Dazu mache ich aber ein neues Thema auf.