www.mikrocontroller.net

Forum: Compiler & IDEs Portierung aus Bascom auf GCC


Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

Erstmal will ich betonen, dass ich euer Forum sehr informativ finde, und 
dass es mir schon oft geholfen hat. Bisher hat mir die Suchfunktion 
jedoch immer ausgereicht. Jetzt sehe ich mich mit einem Mysterium 
konfrontiert. Ich versuche ein Programm, welches in einer (einwandfrei 
funktionierenden) Bascom Variante vorliegt in GCC zu schreiben. Es geht 
um die bedienung eines Modems, welches über das Speicherinterface am 
AT90CAN128 Mikrocontroller angeschlossen ist-

Ich habe das Bascom Programm auf ein minimum reduziert. Das Modem soll 
ein Interrupt auslösen, wenn ein Gültiges Paket hereinkommt. Die dazu 
notwendige Initialisierung ist entsprechend dem Datenblatt des Modems 
korrekt. In der Bascom Version funktioniert alles super und ich kriege 
immer zuverlässige Interrupts.

Das GCC Programm ist in meinen Augen absolut identisch. Es verhält sich 
jedoch anders. Es werden keine Interrupts ausgelöst. Es gibt jedoch 
einen Trick der mich sehr verwirrt: Wenn ich zunächst das Bascom 
Programm raufschreibe und ein Paar Interrupts provozere, und danach das 
GCC Programm raufspiele, dann funktioniert es bis ich ein mal Reset 
drücke. Danach werden wieder keine Interrupts ausgelöst. Wie gesagt, das 
Bascom Programm läuft perfekt. Die Logik sagt mir dass ich irgend etwas 
mit der Interrupt Initialisierung in GCC falsch mache. Ich finde meinen 
Fehler jedoch nicht. Vielleicht könnt ihr mir helfen.

Anbei beide Quellcodes, die Header "LEDS.h" und "UART.h" dürften für das 
Problem nicht von Belangen sein. Bei Bedarf poste ich die aber 
ebenfalls.

Zunächst also das Bascom-Programm:
'///////////////////////////////////////////////////////////////////////////////
'///  File:       Receive_A01.bas
'///  Controller: AT90CAN128
'///  Purpose:    Einfachste Programmversion zu Testzwecken
'///  Autor:      Walter B.
'///  Date:       19.11.2009
'///////////////////////////////////////////////////////////////////////////////

$regfile = "m128can.dat"                                    'Name des Register Files in dem die Adressen der Register usw. stehen
$crystal = 8000000                                          'Frequenz des Quarzes
$baud1 = 57600                                              'Baud-Rate
$hwstack = 32                                               'Größe des Hardware Stacks
$swstack = 10                                               'Größe des Software Stacks
$framesize = 40                                             'Größe des Frame Space

Xmcra = 132

Config Portf.0 = Output                                     'Rote LED
Config Portf.1 = Output                                     'Gelbe LED
Config Portf.2 = Output                                     'Grüne LED

'Aliases für die LEDS zwecks angenehmerer Programmierung
Red_led Alias Portf.0
Yellow_led Alias Portf.1
Green_led Alias Portf.2

Config Portb.5 = Output                                     'OC1A Port Nicht in benutzung
Config Portb.6 = Output                                     'OC1B Port
Config Portd.0 = Input                                      'Modem Interrupt

'Konfiguration der Interrupts wird hier vorgenommen. In unserem Fall gibt es nur
'einen Interrupt vom Modem am Pin D0

On Int0 Modem_isr
Enable Int0
Config Int0 = Falling                                       'Interrupt wird bei fallender Flanke auf Port D0 ausgelöst
Enable Interrupts

Open "com2:" For Binary As #2                               'Ausgabeport festlegen

'///////////////////////////////////////////////////////////////////////////////
'//   Definition der Variablen
'///////////////////////////////////////////////////////////////////////////////

Dim Int_flag As Byte
Dim Status_1 As Byte                                        'Global, da vielerorts benötigt
Dim Status_2 As Byte
Dim Rx_eye_flag As Byte                                     'Signalisiert ob sich das Modem im RX_EYE Modus befindet
Dim Inp1 As Byte
Dim Inp2 As Byte

Set Red_led
Waitms 300                                                  
Reset Red_led
Print #2 , "READY"

Out 10496 , &B01000101                                      'Clock Control 4800bps (meiner Meinung nach 9600)
Waitms 1
Out 17664 , &B00001000                                      'Power_UP 2 RESET
Out 17664 , &B00000001                                      'Power_UP 2 Vbias ON
Out 17408 , &B11101110                                      'Power_UP 1 Clock, BB, Vreg ON, aber VBIAS wird doch so ausgeschaltet?!?!  238 OK
Out 17664 , &B11110001                                      'Power_UP 2 DAC's ON OK
Out 19200 , &B10100001                                      'AUX_DAC_1_MSB TXCO 1.65V OK  'Im Programm ist der Befehl 160
Out 8448 , &B10000100                                       'Main_PLL_M_M 1000 0100
Out 8192 , &B10000000                                       'Main_PLL_M_L 1000 0000
Out 9216 , &B10000000                                       'Main_PLL_N_M 1000 0000
Out 8960 , &B01110101                                       'Main_PLL_N_N 0111 0010
Out 8704 , &B00110000                                       'Main_PLL_N_L 0101 1111
Waitms 10
Out 9728 , &B11000000                                       'Aux_PLL_M_M 1100 0000
Out 9472 , &B10010000                                       'Aux_PLL_M_L 1001 0000
Out 10240 , &B10000111                                      'Aux_PLL_N_M 1000 0111
Out 9984 , &B00001100                                       'Aux_PLL_N_L 0000 1100
Waitms 1
Out 17664 , &B11110101

Do
   Out 16640 , &B00000111                                   'Command RESET
   Inp1 = Inp(16640)                                        'Status_1
   Waitus 10
   Out 17152 , &B10000011                                   'Mode 147
   Waitms 1
   Out 16896 , &B01011100                                   'Control 140
   Waitms 10
   Out 16640 , &B00010000                                   'Command 129
   Waitus 10

   Do
      Idle
   Loop Until Int_flag = 1
   Int_flag = 0

   Status_1 = Inp(16640)                                    'Status_1 einlesen
   Waitus 20
   Print #2 , "/////////////////////////////////////"
   Print #2 , "Status 1:" ; Status_1 ; "=" ; Bin(status_1)
   Status_2 = Inp(17152)                                    'Status_2 einlesen
   Waitus 20
   Print #2 , "Status 2:" ; Status_2 ; "=" ; Bin(status_2)
Loop

End


'///////////////////////////////////////////////////////////////////////////////
'//   MODEM INTERRUPT SERVICE ROUTINE
'///////////////////////////////////////////////////////////////////////////////

Modem_isr:
   Int_flag = 1
Return
Return

Dieses Programm funktioniert perfekt. Nun der entsprechende C-Code:
#ifndef F_CPU
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
#define F_CPU 8000000UL     /* Interner Quarz */
#endif

#include <avr/io.h>        
#include <avr/interrupt.h> 
#include <util/delay.h>     /* in älteren avr-libc Versionen <avr/delay.h> */ 
#include <avr/sleep.h>

#include "LEDS.h" //Initialisierung und Ansteuerung der LEDs
#include "UART.h" //Initialisierung und Ansteuerung des UARTs

volatile uint8_t Modem_INT;

///////////////////////////////////////////////////////////////////////
//
//    HAUPTPROGRAMMSCHLEIFE
//
///////////////////////////////////////////////////////////////////////

void SET_REG(uint16_t ADDRESS, uint8_t Value)
{
  uint8_t *p;
  p = (uint8_t *)ADDRESS;
  *p = Value;
  
}

uint8_t GET_REG(uint16_t ADDRESS)
{
  uint8_t Value;
  uint8_t *p;
  p = (uint8_t *)ADDRESS;
  Value = *p;
  _delay_us(20);
  return Value;
}

int main (void) 
{
  uint8_t Status_1;
  uint8_t Status_2;

  XMCRA = 132;
      
  LED_INIT();
  USART1_INIT();

  DDRD  &= ~_BV(0); 
  EIMSK |= _BV(INT0);
  EICRA |= _BV(ISC01); 
  
  sei(); //Globale Interrupts einschalten

  USART1_INIT();

  SET_LED(RED);
  _delay_ms(300);
  RESET_LED(RED);
  printf("READY\n");

  SET_REG(10496, 0b01000101);//Wirkt sich aus, wie er sollte 4800
  _delay_ms(1);

  //Hier wird die grundsätzliche Initialisierung des Modems vollzogen
  SET_REG(17664, 0b00001000);
  SET_REG(17664, 0b00000001);
  SET_REG(17408, 0b11101110);
  SET_REG(17664, 0b11110001);
  SET_REG(19200, 0b10100001);
  SET_REG(8448, 0b10000100);
  SET_REG(8192, 0b10000000);
  SET_REG(9216, 0b10000000);
  SET_REG(8960, 0b01110101);
  SET_REG(8704, 0b00110000);
  _delay_ms(10);
  SET_REG(9728, 0b11000000);
  SET_REG(9472, 0b10010000);
  SET_REG(10240, 0b10000111);
  SET_REG(9984, 0b00001100);
  _delay_ms(1);
    
  SET_REG(17664, 0b11110101);
  
  while(1) //Hauptschleife
  {   
    SET_REG(16640, 0b00000111); //RESET
    Status_1 = GET_REG(16640); //Auslesen
    _delay_us(10);
    SET_REG(17152, 0b10000011);//Mode Reg
    _delay_ms(1);
    SET_REG(16896, 0b01011100);//Hier schrauben
    _delay_ms(10);
    SET_REG(16640, 0b00010000);
    _delay_us(10);
  
    do
    {
    }while(Modem_INT != 1); //Die schwierigkeit könnte hier liegen
  
    Modem_INT=0;
    
    Status_1 = GET_REG(16640);
    _delay_us(20);
    printf("/////////////////////////////////\n");
    printf("Status 1: %i\n",Status_1);
    Status_2 = GET_REG(17152);
    _delay_us(20);
    printf("Status 2: %i\n",Status_2);
    
  }
   return 0;
}



ISR(INT0_vect)
{
  Modem_INT=1;//Flag setzen
}

Ich sitze schon mehrere Tage an dem Problem und bin langsam ratlos. 
Wahrscheinlich ist es irgend ein Anfänger-Fehler den ich einfach nicht 
sehe. Hoffe ihr könnt mir helfen, vielen Dank.

Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmmm, irgendwie hat das mit der Formatierung nicht geklappt, sorry.

[Edit]
Habe mir die Freiheit genommen, das Problem zu beseitigen.
Rufus

Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, teilweise muten die Kommentare im Quellcode sinnlos an, einfach 
nicht beachten.

Autor: Leo C. (rapid)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hmmm, irgendwie hat das mit der Formatierung nicht geklappt, sorry.

Das liegt wohl am falschen Schrägstrich im schließenden Tag
([\... statt [/...)

Autor: Leo C. (rapid)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich zunächst das Bascom
> Programm raufschreibe und ein Paar Interrupts provozere, und danach das
> GCC Programm raufspiele, dann funktioniert es bis ich ein mal Reset
> drücke. Danach werden wieder keine Interrupts ausgelöst. Wie gesagt, das
> Bascom Programm läuft perfekt. Die Logik sagt mir dass ich irgend etwas
> mit der Interrupt Initialisierung in GCC falsch mache.

Wahrscheinlicher, daß Basic- und C-Programm das Modem unterschiedlich
initialisieren.

Versuch mal folgendes:
void SET_REG(uint16_t ADDRESS, uint8_t Value)
{
  volatile uint8_t *p;
  p = (uint8_t *)ADDRESS;
  *p = Value;

}

uint8_t GET_REG(uint16_t ADDRESS)
{
  uint8_t Value;
  volatile uint8_t *p;
  p = (uint8_t *)ADDRESS;
  Value = *p;
  _delay_us(20);
  return Value;
}

Also p jeweils volatile deklarieren.

> Anbei beide Quellcodes, die Header "LEDS.h" und "UART.h" dürften für das
> Problem nicht von Belangen sein. Bei Bedarf poste ich die aber
> ebenfalls.
leo@cb:~/tmp$ avr-gcc -mmcu=at90can128 -Os -c test.c 
test.c:2:2: warning: #warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
test.c:11:61: error: LEDS.h: Datei oder Verzeichnis nicht gefunden
test.c:12:62: error: UART.h: Datei oder Verzeichnis nicht gefunden
test.c: In function ‘main’:
test.c:58: error: ‘RED’ undeclared (first use in this function)
test.c:58: error: (Each undeclared identifier is reported only once
test.c:58: error: for each function it appears in.)
test.c:61: warning: incompatible implicit declaration of built-in function ‘printf’

Fehlerfrei compilierende Testprogramme sind besser.

Autor: Polonium4U (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Anbei die fehlenden Header. Das mit dem "volatile" werde ich in einer 
Stunde ausprobiert haben, dann meld ich mich nochmal, hört sich aber 
plausibel an, ich habe auch schon die Vermutung gehabt dass meine 
Umsetzung der "Out"- und "Inp"-Bascom Befehle sich in C ein wenig 
unterscheiden könnte. Danke erstmal.

Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

Du hattest tatsächlich Recht. Das hat geholfen. Kannst mir jetzt noch 
einer den Grund erklären? Würds gern verstehen.

Danke

Autor: Leo C. (rapid)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne volatile weiß der Compiler nicht, daß er die Zugriffe auf die
Modemregister nicht (weg-) optimieren darf. Die Adresse 17664 wird z.B.
4 mal beschrieben. Der Compiler schreibt ohne volatile aber nur den 
letzen,
für ihn entgültigen Wert.

Lesen kann er sich ohne volatile ganz sparen, weil er ja weiß, was er 
vorher
reingeschrieben hat, oder weil der Wert im weiteren Programmverlauf 
nicht
verwendet wird.

Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

Danke, hab ich wieder was gelernt. Sehr hilfreich. Vielleicht fehlen bei 
mir ja doch noch ein Paar Grundlagen. Bascom hat mein Gehirn zerfressen.

Autor: Leo C. (rapid)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
> Bascom hat mein Gehirn zerfressen.
g

Hier noch ein paar Vorschläge, damits noch weniger bascomisch und etwas 
C-iger wird:

* In Headerdateien (*.h) nur Deklarationen, keine Funktionsdefinitionen.
  Ausnahme: "static inline".

* Ausschließlich großgeschriebene Bezeichner nur für Makros (#define)
  verwenden.

* Die Funktionen SET_REG() und GET_REG() braucht man nicht.
  Wenn man sie doch verwenden will (Geschmacksache), dann aber klein
  geschrieben, da es ja keine Macros sind.

Im Anhang sieht man vielleicht besser, was ich meine.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst die SET_REG und GET_REG Funktionen weglassen und das ganze 
viel lesbarer machen, indem Du die Registeradressen über #defines 
festlegst

Register im h-File definieren:
#define STATUS_REG    (*(volatile uint8_t *)(16640))
#define MODE_REG      (*(volatile uint8_t *)(17152))
#define SCHRAUB_REG   (*(volatile uint8_t *)(16896))
#define POWER_UP_1    (*(volatile uint8_t *)(17408))
#define POWER_UP_2    (*(volatile uint8_t *)(17664))
#define AUX_DAC_1_MSB (*(volatile uint8_t *)(19200))
#define MAIN_PLL_M_M  (*(volatile uint8_t *)( 8448))
#define MAIN_PLL_M_L  (*(volatile uint8_t *)( 8192))
#define MAIN_PLL_N_M  (*(volatile uint8_t *)( 9216))
#define MAIN_PLL_N_N  (*(volatile uint8_t *)( 8960))
#define AUX_PLL_M_M   (*(volatile uint8_t *)( 9728))
#define AUX_PLL_M_L   (*(volatile uint8_t *)( 9472))
#define AUX_PLL_N_M   (*(volatile uint8_t *)(10240))
#define AUX_PLL_N_L   (*(volatile uint8_t *)( 9984))

und im c-File ganz einfach die Registernamen verwendest statt Adressen
while(1) // Hauptschleife
{   
  STATUS_REG = 0b00000111;  // RESET
  Status_1 = STATUS_REG;    // Auslesen
  _delay_us(10);
  MODE_REG = 0b10000011;    // Mode Reg
  _delay_ms(1);
  SCHRAUB_REG = 0b01011100; // Hier schrauben
  _delay_ms(10);
  STATUS_REG = 0b00010000;
  _delay_us(10);
  do while(Modem_INT != 1); //Die schwierigkeit könnte hier liegen
  Modem_INT=0;
  Status_1 = STATUS_REG;
  _delay_us(20);
  printf("/////////////////////////////////\n");
  printf("Status 1: %i\n",Status_1);
  Status_2 = MODE_REG;
  _delay_us(20);
  printf("Status 2: %i\n",Status_2);
}

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du kannst die SET_REG und GET_REG Funktionen weglassen und das ganze
>viel lesbarer machen, indem Du die Registeradressen über #defines
>festlegst

Das ergibt zudem deutlich kleineren und schnelleren Code als wenn Du es 
mit Funktionen machst...

Autor: Leo C. (rapid)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das ergibt zudem deutlich kleineren und schnelleren Code als wenn Du es
> mit Funktionen machst...

Das nicht, da der Compiler aus den Funktionen den exakt gleichen Code 
erzeugt.

Jedenfalls wenn er wie hier die Funktionen inlinen kann.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jedenfalls wenn er wie hier die Funktionen inlinen kann.

Das "inlinen" klappt aber nur, wenn die Funktion im selben C-Modul 
liegt..

Autor: Polonium4U (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Vielen Dank für die zahlreichen Tipps. Hab meinen Code nun deutlich 
verbessern können.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.