Forum: Compiler & IDEs Portierung aus Bascom auf GCC


von Polonium4U (Gast)


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:
1
'///////////////////////////////////////////////////////////////////////////////
2
'///  File:       Receive_A01.bas
3
'///  Controller: AT90CAN128
4
'///  Purpose:    Einfachste Programmversion zu Testzwecken
5
'///  Autor:      Walter B.
6
'///  Date:       19.11.2009
7
'///////////////////////////////////////////////////////////////////////////////
8
9
$regfile = "m128can.dat"                                    'Name des Register Files in dem die Adressen der Register usw. stehen
10
$crystal = 8000000                                          'Frequenz des Quarzes
11
$baud1 = 57600                                              'Baud-Rate
12
$hwstack = 32                                               'Größe des Hardware Stacks
13
$swstack = 10                                               'Größe des Software Stacks
14
$framesize = 40                                             'Größe des Frame Space
15
16
Xmcra = 132
17
18
Config Portf.0 = Output                                     'Rote LED
19
Config Portf.1 = Output                                     'Gelbe LED
20
Config Portf.2 = Output                                     'Grüne LED
21
22
'Aliases für die LEDS zwecks angenehmerer Programmierung
23
Red_led Alias Portf.0
24
Yellow_led Alias Portf.1
25
Green_led Alias Portf.2
26
27
Config Portb.5 = Output                                     'OC1A Port Nicht in benutzung
28
Config Portb.6 = Output                                     'OC1B Port
29
Config Portd.0 = Input                                      'Modem Interrupt
30
31
'Konfiguration der Interrupts wird hier vorgenommen. In unserem Fall gibt es nur
32
'einen Interrupt vom Modem am Pin D0
33
34
On Int0 Modem_isr
35
Enable Int0
36
Config Int0 = Falling                                       'Interrupt wird bei fallender Flanke auf Port D0 ausgelöst
37
Enable Interrupts
38
39
Open "com2:" For Binary As #2                               'Ausgabeport festlegen
40
41
'///////////////////////////////////////////////////////////////////////////////
42
'//   Definition der Variablen
43
'///////////////////////////////////////////////////////////////////////////////
44
45
Dim Int_flag As Byte
46
Dim Status_1 As Byte                                        'Global, da vielerorts benötigt
47
Dim Status_2 As Byte
48
Dim Rx_eye_flag As Byte                                     'Signalisiert ob sich das Modem im RX_EYE Modus befindet
49
Dim Inp1 As Byte
50
Dim Inp2 As Byte
51
52
Set Red_led
53
Waitms 300                                                  
54
Reset Red_led
55
Print #2 , "READY"
56
57
Out 10496 , &B01000101                                      'Clock Control 4800bps (meiner Meinung nach 9600)
58
Waitms 1
59
Out 17664 , &B00001000                                      'Power_UP 2 RESET
60
Out 17664 , &B00000001                                      'Power_UP 2 Vbias ON
61
Out 17408 , &B11101110                                      'Power_UP 1 Clock, BB, Vreg ON, aber VBIAS wird doch so ausgeschaltet?!?!  238 OK
62
Out 17664 , &B11110001                                      'Power_UP 2 DAC's ON OK
63
Out 19200 , &B10100001                                      'AUX_DAC_1_MSB TXCO 1.65V OK  'Im Programm ist der Befehl 160
64
Out 8448 , &B10000100                                       'Main_PLL_M_M 1000 0100
65
Out 8192 , &B10000000                                       'Main_PLL_M_L 1000 0000
66
Out 9216 , &B10000000                                       'Main_PLL_N_M 1000 0000
67
Out 8960 , &B01110101                                       'Main_PLL_N_N 0111 0010
68
Out 8704 , &B00110000                                       'Main_PLL_N_L 0101 1111
69
Waitms 10
70
Out 9728 , &B11000000                                       'Aux_PLL_M_M 1100 0000
71
Out 9472 , &B10010000                                       'Aux_PLL_M_L 1001 0000
72
Out 10240 , &B10000111                                      'Aux_PLL_N_M 1000 0111
73
Out 9984 , &B00001100                                       'Aux_PLL_N_L 0000 1100
74
Waitms 1
75
Out 17664 , &B11110101
76
77
Do
78
   Out 16640 , &B00000111                                   'Command RESET
79
   Inp1 = Inp(16640)                                        'Status_1
80
   Waitus 10
81
   Out 17152 , &B10000011                                   'Mode 147
82
   Waitms 1
83
   Out 16896 , &B01011100                                   'Control 140
84
   Waitms 10
85
   Out 16640 , &B00010000                                   'Command 129
86
   Waitus 10
87
88
   Do
89
      Idle
90
   Loop Until Int_flag = 1
91
   Int_flag = 0
92
93
   Status_1 = Inp(16640)                                    'Status_1 einlesen
94
   Waitus 20
95
   Print #2 , "/////////////////////////////////////"
96
   Print #2 , "Status 1:" ; Status_1 ; "=" ; Bin(status_1)
97
   Status_2 = Inp(17152)                                    'Status_2 einlesen
98
   Waitus 20
99
   Print #2 , "Status 2:" ; Status_2 ; "=" ; Bin(status_2)
100
Loop
101
102
End
103
104
105
'///////////////////////////////////////////////////////////////////////////////
106
'//   MODEM INTERRUPT SERVICE ROUTINE
107
'///////////////////////////////////////////////////////////////////////////////
108
109
Modem_isr:
110
   Int_flag = 1
111
Return
112
Return

Dieses Programm funktioniert perfekt. Nun der entsprechende C-Code:
1
#ifndef F_CPU
2
#warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
3
#define F_CPU 8000000UL     /* Interner Quarz */
4
#endif
5
6
#include <avr/io.h>        
7
#include <avr/interrupt.h> 
8
#include <util/delay.h>     /* in älteren avr-libc Versionen <avr/delay.h> */ 
9
#include <avr/sleep.h>
10
11
#include "LEDS.h" //Initialisierung und Ansteuerung der LEDs
12
#include "UART.h" //Initialisierung und Ansteuerung des UARTs
13
14
volatile uint8_t Modem_INT;
15
16
///////////////////////////////////////////////////////////////////////
17
//
18
//    HAUPTPROGRAMMSCHLEIFE
19
//
20
///////////////////////////////////////////////////////////////////////
21
22
void SET_REG(uint16_t ADDRESS, uint8_t Value)
23
{
24
  uint8_t *p;
25
  p = (uint8_t *)ADDRESS;
26
  *p = Value;
27
  
28
}
29
30
uint8_t GET_REG(uint16_t ADDRESS)
31
{
32
  uint8_t Value;
33
  uint8_t *p;
34
  p = (uint8_t *)ADDRESS;
35
  Value = *p;
36
  _delay_us(20);
37
  return Value;
38
}
39
40
int main (void) 
41
{
42
  uint8_t Status_1;
43
  uint8_t Status_2;
44
45
  XMCRA = 132;
46
      
47
  LED_INIT();
48
  USART1_INIT();
49
50
  DDRD  &= ~_BV(0); 
51
  EIMSK |= _BV(INT0);
52
  EICRA |= _BV(ISC01); 
53
  
54
  sei(); //Globale Interrupts einschalten
55
56
  USART1_INIT();
57
58
  SET_LED(RED);
59
  _delay_ms(300);
60
  RESET_LED(RED);
61
  printf("READY\n");
62
63
  SET_REG(10496, 0b01000101);//Wirkt sich aus, wie er sollte 4800
64
  _delay_ms(1);
65
66
  //Hier wird die grundsätzliche Initialisierung des Modems vollzogen
67
  SET_REG(17664, 0b00001000);
68
  SET_REG(17664, 0b00000001);
69
  SET_REG(17408, 0b11101110);
70
  SET_REG(17664, 0b11110001);
71
  SET_REG(19200, 0b10100001);
72
  SET_REG(8448, 0b10000100);
73
  SET_REG(8192, 0b10000000);
74
  SET_REG(9216, 0b10000000);
75
  SET_REG(8960, 0b01110101);
76
  SET_REG(8704, 0b00110000);
77
  _delay_ms(10);
78
  SET_REG(9728, 0b11000000);
79
  SET_REG(9472, 0b10010000);
80
  SET_REG(10240, 0b10000111);
81
  SET_REG(9984, 0b00001100);
82
  _delay_ms(1);
83
    
84
  SET_REG(17664, 0b11110101);
85
  
86
  while(1) //Hauptschleife
87
  {   
88
    SET_REG(16640, 0b00000111); //RESET
89
    Status_1 = GET_REG(16640); //Auslesen
90
    _delay_us(10);
91
    SET_REG(17152, 0b10000011);//Mode Reg
92
    _delay_ms(1);
93
    SET_REG(16896, 0b01011100);//Hier schrauben
94
    _delay_ms(10);
95
    SET_REG(16640, 0b00010000);
96
    _delay_us(10);
97
  
98
    do
99
    {
100
    }while(Modem_INT != 1); //Die schwierigkeit könnte hier liegen
101
  
102
    Modem_INT=0;
103
    
104
    Status_1 = GET_REG(16640);
105
    _delay_us(20);
106
    printf("/////////////////////////////////\n");
107
    printf("Status 1: %i\n",Status_1);
108
    Status_2 = GET_REG(17152);
109
    _delay_us(20);
110
    printf("Status 2: %i\n",Status_2);
111
    
112
  }
113
   return 0;
114
}
115
116
117
118
ISR(INT0_vect)
119
{
120
  Modem_INT=1;//Flag setzen
121
}

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.

von Polonium4U (Gast)


Lesenswert?

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

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

von Polonium4U (Gast)


Lesenswert?

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

von Leo C. (rapid)


Lesenswert?

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

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

von Leo C. (rapid)


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:
1
void SET_REG(uint16_t ADDRESS, uint8_t Value)
2
{
3
  volatile uint8_t *p;
4
  p = (uint8_t *)ADDRESS;
5
  *p = Value;
6
7
}
8
9
uint8_t GET_REG(uint16_t ADDRESS)
10
{
11
  uint8_t Value;
12
  volatile uint8_t *p;
13
  p = (uint8_t *)ADDRESS;
14
  Value = *p;
15
  _delay_us(20);
16
  return Value;
17
}

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.
1
leo@cb:~/tmp$ avr-gcc -mmcu=at90can128 -Os -c test.c 
2
test.c:2:2: warning: #warning "F_CPU war noch nicht definiert, wird nun mit 8000000 definiert"
3
test.c:11:61: error: LEDS.h: Datei oder Verzeichnis nicht gefunden
4
test.c:12:62: error: UART.h: Datei oder Verzeichnis nicht gefunden
5
test.c: In function ‘main’:
6
test.c:58: error: ‘RED’ undeclared (first use in this function)
7
test.c:58: error: (Each undeclared identifier is reported only once
8
test.c:58: error: for each function it appears in.)
9
test.c:61: warning: incompatible implicit declaration of built-in function ‘printf’

Fehlerfrei compilierende Testprogramme sind besser.

von Polonium4U (Gast)


Angehängte Dateien:

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.

von Polonium4U (Gast)


Lesenswert?

Hey,

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

Danke

von Leo C. (rapid)


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.

von Polonium4U (Gast)


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.

von Leo C. (rapid)


Angehängte Dateien:

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.

von Peter (Gast)


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:
1
#define STATUS_REG    (*(volatile uint8_t *)(16640))
2
#define MODE_REG      (*(volatile uint8_t *)(17152))
3
#define SCHRAUB_REG   (*(volatile uint8_t *)(16896))
4
#define POWER_UP_1    (*(volatile uint8_t *)(17408))
5
#define POWER_UP_2    (*(volatile uint8_t *)(17664))
6
#define AUX_DAC_1_MSB (*(volatile uint8_t *)(19200))
7
#define MAIN_PLL_M_M  (*(volatile uint8_t *)( 8448))
8
#define MAIN_PLL_M_L  (*(volatile uint8_t *)( 8192))
9
#define MAIN_PLL_N_M  (*(volatile uint8_t *)( 9216))
10
#define MAIN_PLL_N_N  (*(volatile uint8_t *)( 8960))
11
#define AUX_PLL_M_M   (*(volatile uint8_t *)( 9728))
12
#define AUX_PLL_M_L   (*(volatile uint8_t *)( 9472))
13
#define AUX_PLL_N_M   (*(volatile uint8_t *)(10240))
14
#define AUX_PLL_N_L   (*(volatile uint8_t *)( 9984))

und im c-File ganz einfach die Registernamen verwendest statt Adressen
1
while(1) // Hauptschleife
2
{   
3
  STATUS_REG = 0b00000111;  // RESET
4
  Status_1 = STATUS_REG;    // Auslesen
5
  _delay_us(10);
6
  MODE_REG = 0b10000011;    // Mode Reg
7
  _delay_ms(1);
8
  SCHRAUB_REG = 0b01011100; // Hier schrauben
9
  _delay_ms(10);
10
  STATUS_REG = 0b00010000;
11
  _delay_us(10);
12
  do while(Modem_INT != 1); //Die schwierigkeit könnte hier liegen
13
  Modem_INT=0;
14
  Status_1 = STATUS_REG;
15
  _delay_us(20);
16
  printf("/////////////////////////////////\n");
17
  printf("Status 1: %i\n",Status_1);
18
  Status_2 = MODE_REG;
19
  _delay_us(20);
20
  printf("Status 2: %i\n",Status_2);
21
}

von Peter (Gast)


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...

von Leo C. (rapid)


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.

von Peter (Gast)


Lesenswert?

>Jedenfalls wenn er wie hier die Funktionen inlinen kann.

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

von Polonium4U (Gast)


Lesenswert?

Hallo,

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.