Forum: Mikrocontroller und Digitale Elektronik MSP430 TimerA langsamer als erwartet?


von ToMa (Gast)


Lesenswert?

Hallo,
ich verwende ein Launchpad MSP430F2274. Bei dem wollte ich einen Timer 
einstellen, sodass aller 5 Sekunden eine (blockierende) Funktion aus 
LPM3 heraus aufgerufen wird. Dazu eine Verständnisfrage und eine 
Seltsamkeit, mit der Bitte auf Aufklärung :)

1. Im TimerA-ISR soll erstmal einfach nur der LPM3 verlassen werden.
1
#pragma vector=TIMERA0_VECTOR
2
__interrupt void Timer_A (void)
3
{
4
    LPM3_EXIT;                       
5
}

In der main dann Folgendes:
1
_EINT();
2
  
3
 while(1){  
4
   enter_LPM3; 
5
   meineFunktion();
6
  }
Wenn während der Abarbeitung der Funktion wieder ein Timer-Interrupt 
erfolgt, läuft die Funktion dann korrekt weiter? Sollte doch eigentlich 
gewährleistet sein? Die Funktion dauert sagen wir mal max. 1 Sekunde, 
Interrupt aller 0,5 Sek, siehe nächsten Punkt. Ändert es was, wenn die 
Funktion von UART-Interrupts abhängt?

2.
1
  P1DIR |= LED0;                           // P1.0 output
2
  P1OUT |= LED0;                           // P1.0 default ON
3
4
  TACTL = TACLR;                           
5
  TACTL = TASSEL_1+ID_3;                   // 1 ACLK, 2 SMCLK
6
  TACCTL0 = OUTMOD_4 + CCIE;               // Toggle Output, CCR0 interrupt enabled
7
  TACCR0 = 62500;                         //theoretisch 0,5s@1MHz
8
  TACTL |= MC_1;                         //  UP mode
So ist der Timer initialisiert. Ich würde mit ACLK oder SMCLK bei 
jeweils 1MHz/8 und TACCR0 = 62500 ein halbsekündiges Togglen der LED 
erwarten. Die Led ist aber ca. 15s an bzw. aus. Was ist falsch?

von ToMa (Gast)


Lesenswert?

LPM0 natürlich

von so nicht (Gast)


Lesenswert?

ToMa schrieb:
> Was ist falsch?

Du zeigst nicht das ganze Programm. Niemand hat Lust in den Fragmenten 
zu stöbern, owohl der Fehler in der nicht gezeigten Zeile 42 steckt.

von ToMa (Gast)


Lesenswert?

Und wer hat Lust, im gesamten Quellcode zu stöbern?  Ich bin weg. Danke 
für nichts, Forum.

von ToMa (Gast)


Lesenswert?

Entschuldigt, ich habe überreagiert. Ich bin nur etwas frustriert, da 
ich früher das Feedback erhielt, "schreib nicht einfach deinen ganzen 
Code her, wer soll sich da durchwühlen". Und jetzt lese ich das 
Gegenteil. Sorry.
Das Timing der LEDs klappt jetzt. Wenn ich jetzt aber meine Funktion 
reinbringe, wird die main-while nciht mehr komplett abgearbeitet. (LED2 
blinkt nicht)
1
#include <msp430.h>
2
#include <stdint.h>
3
4
#define SPI_MODE0    (0+UCCKPH)         ///< CPOL = 0, CPHA = 0 
5
#define SPI_MODE1    (0+UCCKPL+UCCKPH)  ///< CPOL = 0, CPHA = 1 
6
#define SPI_MODE2    (0)                ///< CPOL = 1, CPHA = 0 
7
#define SPI_MODE3    (0+UCCKPL)         ///< CPOL = 1, CPHA = 1 
8
9
#define MOSI         BIT1
10
#define MISO         BIT2
11
#define SPICLK       BIT3
12
#define SEN_AMS      BIT4
13
14
#define SEN_AMS_SELECT   P1OUT |= BIT4;
15
#define SEN_AMS_UNSELECT P1OUT &= ~BIT4;
16
17
#define DUMMY_A         0xAA
18
#define DUMMY_0         0x00
19
20
#define AMSRESET        0xC0
21
#define GETTEMP         0xC1
22
#define GETBATT         0xC2
23
#define GETSTAT         0xC7
24
#define GETFIFO         0xE0
25
#define SETFIFO         0xE1
26
27
#define LED0        BIT0 //Timer A
28
#define LED2        BIT2 //Timer A
29
30
// ################# Variablen #################################################
31
32
unsigned char sen_data[]         = {0xAA, 0xAA, 0xAA, 0xAA};  //Interner Sensor/Spannung
33
unsigned char rcv_data[]         = {0xAB, 0xAB, 0xAB, 0xAB};  //Lesepuffer EEPROM
34
unsigned char tsm_data[]         = {0xAC, 0xAE, 0xAF, 0xAC};  //Schreibpuffer EEPROM
35
int fillthatarray = 0;
36
uint16_t addr = 0x064;
37
38
unsigned char intvl_count = 19;  // 1 sec
39
unsigned char i = 0;             // 10sec
40
41
// ################# Prototypen ################################################
42
void clk_init(void);
43
44
void spib_init(void);
45
unsigned char spib_write_read_byte(unsigned char);
46
47
void ams_init(void);
48
void ams_command_read_internal16(unsigned char);
49
void ams_command_writeEEPROM(uint16_t, unsigned char);
50
void ams_command_readEEPROM(uint16_t address, unsigned char numberOfBytes);
51
52
void timera_init(void);
53
54
// ################# MAIN ######################################################
55
void main(void)
56
{
57
  WDTCTL = WDTPW + WDTHOLD;                     // Stop WDT
58
59
  clk_init();
60
  timera_init();
61
 // spib_init();
62
 // ams_init();
63
  
64
65
  
66
  //Schreibe 4 Byte User Speicher
67
 // ams_command_writeEEPROM(addr, tsm_data[0]);
68
//  ams_command_writeEEPROM(addr+1,tsm_data[1]);
69
//  ams_command_writeEEPROM(addr+2,tsm_data[2]);
70
//  ams_command_writeEEPROM(addr+3,tsm_data[3]);
71
  //Lese fortlaufend User Speicher
72
//  ams_command_readEEPROM(addr, 4); 
73
//  __delay_cycles(1);
74
 
75
  _EINT();
76
  
77
  for(;;){  
78
    LPM0; 
79
    //lese Temperatur/Spannung
80
    ams_command_read_internal16(GETTEMP);
81
    ams_command_read_internal16(GETBATT);
82
    P1OUT ^= LED2;
83
    intvl_count=19;
84
    i++;
85
  }
86
}
87
88
// ################# Timer A #####################################################
89
void timera_init(void){
90
91
  P1DIR |= LED0 + LED2;                          // P1.0 output
92
  P1OUT &= ~LED0;
93
  P1OUT &= ~LED2;
94
  
95
  TACTL = TACLR;      
96
  TACCTL0 = CCIE;                                // Toggle Output, CCR0 interrupt enabled
97
  TACTL = MC_1 + TASSEL_2+ID_3;                  // 1 ACLK, 2 SMCLK
98
  TACCR0 = 62500;                                //62500 
99
  
100
}
101
102
// Timer A0 interrupt service routine
103
#pragma vector=TIMERA0_VECTOR
104
__interrupt void Timer_A (void)
105
{
106
  //CCR0++;                                                                 // Add Offset to CCR0
107
  P1OUT ^= LED0;
108
  if (intvl_count ==0){ 
109
   LPM0_EXIT;
110
  }else {
111
    intvl_count--;
112
  }                        
113
}
114
115
// ################# Clock #####################################################
116
void clk_init(void){
117
118
  if (CALBC1_1MHZ==0xFF)        // If calibration constant erased
119
  {                      
120
    while(1);                               // trap CPU
121
  }
122
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
123
  BCSCTL1 = CALBC1_1MHZ;                   // Set DCO to 8MHz
124
  DCOCTL = CALDCO_1MHZ;
125
}
126
127
// ################# SPI ######################################################
128
//SPI Initialisation
129
void spib_init(){
130
  P3SEL  = MOSI + MISO + SPICLK;             // P3.2=MISO, P3.1=MOSI, P3.3=CLK
131
  P3DIR |= SPICLK + MOSI;                     
132
  P3DIR &= ~MISO;
133
  
134
  UCB0CTL0 |= UCMSB + UCMST + UCSYNC + SPI_MODE2; // MAX: SPI Mode "2"=3 (max+ams?) oder "3"=1 (nur max), MSB zuerst, 8-Bit
135
  UCB0CTL1 |= UCSSEL_2;                           // Clock
136
  UCB0BR0 |= 0x08;                                // Clock prescaler
137
  UCB0BR1 = 0;                                   
138
  UCB0CTL1 &= ~UCSWRST;                           // Beende Reset State USCI
139
}
140
141
//Basic RX/TX
142
unsigned char spib_write_read_byte(unsigned char data){
143
    unsigned char content;
144
 
145
    UCB0TXBUF = data;                       // Dummy write to start SPI
146
    while (!(IFG2 & UCB0RXIFG));            // USCI_B0 RX buffer ready?
147
    content = UCB0RXBUF;                     
148
    
149
    return content;
150
}
151
152
// ################# AMS Tag ###################################################
153
void ams_init(void){
154
 // P1OUT |= CS_AMS;                         
155
  P1OUT &= ~SEN_AMS;    
156
  P1DIR |= SEN_AMS;                           // P1.4 als Ausgang für CS_AMS
157
  
158
  SEN_AMS_SELECT;  
159
    __delay_cycles(200);                 
160
    (void)spib_write_read_byte(AMSRESET); 
161
  SEN_AMS_UNSELECT; 
162
   
163
  __delay_cycles(2000);
164
}
165
166
void ams_command_writeEEPROM(uint16_t address, unsigned char data){
167
   SEN_AMS_SELECT;  
168
    __delay_cycles(150);                 
169
    (void)spib_write_read_byte(address>>8);  //write command + a10-a8
170
    (void)spib_write_read_byte(address);  
171
    
172
    (void)spib_write_read_byte(data);  ///data     
173
    __delay_cycles(8000); 
174
  SEN_AMS_UNSELECT;  
175
}
176
177
void ams_command_readEEPROM(uint16_t address, unsigned char numberOfBytes){
178
   SEN_AMS_SELECT;  
179
    __delay_cycles(160);   
180
    (void)spib_write_read_byte(address >> 8 | 0x40);  //read command  + a10-a8
181
    (void)spib_write_read_byte(address);  
182
    
183
    __delay_cycles(500);
184
    for (int i =0; i< numberOfBytes; i++){
185
    rcv_data[i]  = spib_write_read_byte(DUMMY_0);
186
    }
187
  SEN_AMS_UNSELECT;  
188
}
189
190
void ams_command_read_internal16(unsigned char command){
191
  SEN_AMS_SELECT;  
192
    __delay_cycles(160);                 
193
    (void)spib_write_read_byte(command);  
194
    __delay_cycles(10000);      
195
    //while (!UCB0RXBUF);
196
    sen_data[fillthatarray]  = spib_write_read_byte(DUMMY_A);
197
    sen_data[fillthatarray+1]  = spib_write_read_byte(DUMMY_A);
198
    fillthatarray += 2;
199
  SEN_AMS_UNSELECT;  
200
}

von so nicht (Gast)


Lesenswert?

ToMa schrieb:
> unsigned char intvl_count = 19;  // 1 sec
> ...

versuch 's mal mit volatile.

von wv (Gast)


Lesenswert?

Hallo ToMa

erstmal die Frage zum Interrupt:

der Interrupt unterbricht das Hauptprogramm, springt in die ISR, 
arbeitet sie ab und fährt danach wieder an der gleichen Stelle vom 
Hauptprogramm fort. Wenn der MSP430 vorher im Schlafmodus war, kommt es 
darauf an, ob die Interruptroutine mit LPMx_EXIT verlassen wurde oder 
nicht, je nachdem schläft er also weiter im Haupprogramm oder wird 
aufgeweckt und startet bei

LPM0;

Problem in Deinem Programm ist, dass Du den Schleifenzähler im 
Hauptprogram setzt und in der ISR abwärts zählst. Volatile hilft da nur 
zum Teil, denn es kann ja auch sein, dass beim Beenden der ISR mit 
LPM0_Exit gerade ein Lesevorgang solange dauert, dass der Timer erneut 
auslöst und die Zeile

intvl_count=19;

nicht erreicht wird.

Wahrscheinlich hängt einer der beiden Lesevorgänge, das sollte man mit 
dem Debugger aber rauskriegen.

Gruß wv

von so nicht (Gast)


Lesenswert?

Blödsinn, der int wird immer auf einmal gelesen. Entweder sieht die ISR 
ne 0 oder einen positiven Wert. Darf auch unsigned sein.

LPM0_EXIT muss aber LPM verlassen!

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.