Forum: Mikrocontroller und Digitale Elektronik Timer-Interrupt bei ATTiny2313 kommt nicht


von Jens K. (mister232)


Lesenswert?

Ich versuche mich gerade an der Programmierung einer SPI-Schnittstelle 
mittels des USI-Interfaces eines ATTiny2313. Ich habe dazu Code von 
Atmel gefunden, welchen ich für meine Anwendung angepasst habe. Um den 
Clock zu erzeugen nutze ich den Timer0 mit dem Compare-Interrupt A. Hier 
die Initialisierung des SPI-Master und des Timers, wie gesagt, dass 
meiste ist von Atmel übernommen:
1
/*
2
 * SPI.c
3
 *
4
 * Created: 13.09.2004 12:08:54
5
 * Author: Atmel
6
 * Changed: 19.08.2014 17:48:49, J.Kathe
7
 *
8
 * Control and initialization functions for an USI SPI-Interface on an AVR. Written by Atmel
9
 */ 
10
11
#include "USI_SPI.h"
12
#include <avr/io.h>
13
#include <avr/interrupt.h>
14
#include <util/delay.h>
15
16
/* USI port and pin definitions.
17
 */
18
#define USI_OUT_REG  PORTB  //!< USI port output register.
19
#define USI_DIR_REG  DDRB  //!< USI port direction register.
20
#define USI_CLOCK_PIN  PB7  //!< USI clock I/O pin.
21
#define USI_DATAIN_PIN  PB5  //!< USI data input pin.
22
#define USI_DATAOUT_PIN  PB6  //!< USI data output pin.
23
#define USI_nSS_PIN PB4    //!< USI slave-select pin
24
25
26
27
28
/*  Speed configuration:
29
 *  Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2.
30
 *  Maximum = CPUSPEED / 64.
31
 */
32
#define TC0_PRESCALER_VALUE 256  //!< Must be 1, 8, 64, 256 or 1024.
33
#define TC0_COMPARE_VALUE   1  //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1.
34
35
36
37
38
/*  Prescaler value converted to bit settings.
39
 */
40
#if TC0_PRESCALER_VALUE == 1
41
  #define TC0_PS_SETTING (1<<CS00)
42
#elif TC0_PRESCALER_VALUE == 8
43
  #define TC0_PS_SETTING (1<<CS01)
44
#elif TC0_PRESCALER_VALUE == 64
45
  #define TC0_PS_SETTING (1<<CS01)|(1<<CS00)
46
#elif TC0_PRESCALER_VALUE == 256
47
  #define TC0_PS_SETTING (1<<CS02)
48
#elif TC0_PRESCALER_VALUE == 1024
49
  #define TC0_PS_SETTING (1<<CS02)|(1<<CS00)
50
#else
51
  #error Invalid T/C0 prescaler setting.
52
#endif
53
54
55
56
/*! \brief  Data input register buffer.
57
 *
58
 *  Incoming bytes are stored in this byte until the next transfer is complete.
59
 *  This byte can be used the same way as the SPI data register in the native
60
 *  SPI module, which means that the byte must be read before the next transfer
61
 *  completes and overwrites the current value.
62
 */
63
unsigned char storedUSIDR;
64
65
66
67
/*! \brief  Driver status bit structure.
68
 *
69
 *  This struct contains status flags for the driver.
70
 *  The flags have the same meaning as the corresponding status flags
71
 *  for the native SPI module. The flags should not be changed by the user.
72
 *  The driver takes care of updating the flags when required.
73
 */
74
struct usidriverStatus_t {
75
  unsigned char masterMode : 1;       //!< True if in master mode.
76
  unsigned char transferComplete : 1; //!< True when transfer completed.
77
  unsigned char writeCollision : 1;   //!< True if put attempted during transfer.
78
};
79
80
volatile struct usidriverStatus_t spiX_status; //!< The driver status bits.
81
82
83
84
// Change for SPI-Slave!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
85
ISR(TIMER0_COMPA_vect)
86
{
87
  USICR |= (1<<USITC);  // Toggle clock output pin.
88
  
89
  //wait for next transmission
90
  PORTD |= (1<<PD4);
91
  _delay_ms(500);
92
  PORTD &= ~(1<<PD4);
93
  _delay_ms(500);
94
}
95
96
97
98
/*! \brief  USI Timer Overflow Interrupt handler.
99
 *
100
 *  This handler disables the compare match interrupt if in master mode.
101
 *  When the USI counter overflows, a byte has been transferred, and we
102
 *  have to stop the timer tick.
103
 *  For all modes the USIDR contents are stored and flags are updated.
104
 */
105
ISR( USI_OVERFLOW_vect )
106
{
107
  // Master must now disable the compare match interrupt
108
  // to prevent more USI counter clocks.
109
  if( spiX_status.masterMode == 1 ) {
110
    TIMSK &= ~(1<<OCIE0A);
111
  }
112
  
113
  // Update flags and clear USI counter
114
  USISR = (1<<USIOIF);
115
  spiX_status.transferComplete = 1;
116
117
  // Copy USIDR to buffer to prevent overwrite on next transfer.
118
  storedUSIDR = USIDR;
119
}
120
121
122
123
/*! \brief  Initialize USI as SPI master.
124
 *
125
 *  This function sets up all pin directions and module configurations.
126
 *  Use this function initially or when changing from slave to master mode.
127
 *  Note that the stored USIDR value is cleared.
128
 *
129
 *  \param spi_mode  Required SPI mode, must be 0 or 1.
130
 */
131
void spiX_initmaster( char spi_mode )
132
{
133
  // Configure port directions.
134
  USI_DIR_REG |= (1<<USI_DATAOUT_PIN) | (1<<USI_CLOCK_PIN) | (1<<USI_nSS_PIN); // Outputs.
135
  USI_DIR_REG &= ~(1<<USI_DATAIN_PIN);                      // Inputs.
136
  USI_OUT_REG |= (1<<USI_DATAIN_PIN);                       // Pull-ups.
137
  
138
  // Pull nSS up, so no slave is selected
139
  PORTB |= (1<<USI_nSS_PIN);
140
  
141
  // Configure USI to 3-wire master mode with overflow interrupt.
142
  USICR = (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (spi_mode<<USICS0) | (1<<USICLK);
143
144
  // Enable 'Clear Timer on Compare match' and init prescaler.
145
  TCCR0A |= (1<<WGM01) | (1<<WGM00);
146
  TCCR0B |= (1<<TC0_PS_SETTING);
147
148
  // Init Output Compare Register.
149
  OCR0A = TC0_COMPARE_VALUE;
150
  
151
  // Init driver status register.
152
  spiX_status.masterMode       = 1;
153
  spiX_status.transferComplete = 0;
154
  spiX_status.writeCollision   = 0;
155
  
156
  storedUSIDR = 0;
157
}
158
159
160
161
/*! \brief  Initialize USI as SPI slave.
162
 *
163
 *  This function sets up all pin directions and module configurations.
164
 *  Use this function initially or when changing from master to slave mode.
165
 *  Note that the stored USIDR value is cleared.
166
 *
167
 *  \param spi_mode  Required SPI mode, must be 0 or 1.
168
 */
169
void spiX_initslave( char spi_mode )
170
{
171
  // Configure port directions.
172
  USI_DIR_REG |= (1<<USI_DATAOUT_PIN); // Outputs.
173
  USI_DIR_REG &= ~(1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN) | ~(1<<USI_nSS_PIN); // Inputs.
174
  USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN) | (1<<USI_nSS_PIN);  // Pull-ups.
175
  
176
  // Configure USI to 3-wire slave mode with overflow interrupt.
177
  USICR = (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (spi_mode<<USICS0);
178
  
179
  // Init driver status register.
180
  spiX_status.masterMode       = 0;
181
  spiX_status.transferComplete = 0;
182
  spiX_status.writeCollision   = 0;
183
  
184
  storedUSIDR = 0;
185
}
186
187
188
189
/*! \brief  Put one byte on bus.
190
 *
191
 *  Use this function like you would write to the SPDR register in the native SPI module.
192
 *  Calling this function in master mode starts a transfer, while in slave mode, a
193
 *  byte will be prepared for the next transfer initiated by the master device.
194
 *  If a transfer is in progress, this function will set the write collision flag
195
 *  and return without altering the data registers.
196
 *
197
 *  \returns  0 if a write collision occurred, 1 otherwise.
198
 */
199
char spiX_put( unsigned char val )
200
{
201
  // Check if transmission in progress,
202
  // i.e. USI counter unequal to zero.
203
  if( (USISR & 0x0F) != 0 ) {
204
    // Indicate write collision and return.
205
    spiX_status.writeCollision = 1;
206
    return 0;
207
  }
208
  
209
  // Reinit flags.
210
  spiX_status.transferComplete = 0;
211
  spiX_status.writeCollision = 0;
212
213
  // Put data in USI data register.
214
  USIDR = val;
215
  
216
  // Pull nSS down, so slave is selected
217
  PORTB &= ~(1<<USI_nSS_PIN);
218
  
219
  // Master should now enable compare match interrupts.
220
  if( spiX_status.masterMode == 1 ) {
221
    TIFR |= (1<<OCF0A);   // Clear compare match flag.
222
    TIMSK |= (1<<OCIE0A); // Enable compare match interrupt.
223
  }
224
225
  if( spiX_status.writeCollision == 0 ) return 1;
226
  return 0;
227
}
228
229
230
231
/*! \brief  Get one byte from bus.
232
 *
233
 *  This function only returns the previous stored USIDR value.
234
 *  The transfer complete flag is not checked. Use this function
235
 *  like you would read from the SPDR register in the native SPI module.
236
 */
237
unsigned char spiX_get()
238
{
239
  return storedUSIDR;
240
}
241
242
243
244
/*! \brief  Wait for transfer to complete.
245
 *
246
 *  This function waits until the transfer complete flag is set.
247
 *  Use this function like you would wait for the native SPI interrupt flag.
248
 */
249
void spiX_wait()
250
{
251
  //do {} while( spiX_status.transferComplete == 0 );
252
    
253
  // Pull nSS up, so no slave is selected
254
  PORTB |= (1<<USI_nSS_PIN);
255
}
256
257
258
259
// end of file

Und hier noch die Main:
1
#include "USI_SPI.h"
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
7
int main(void)
8
{
9
  unsigned short loopCNT;
10
  char val;
11
  
12
  // Initialize pin for LED
13
  DDRD |= (1<<PD4);
14
  
15
  // Initialize USI-Interface as SPI master
16
  spiX_initmaster(SPIMODE);
17
  
18
  // Global enable interrupts
19
  sei();
20
  
21
  // Toggle LED to check it
22
  for(loopCNT = 0; loopCNT < 3; loopCNT++)
23
  {
24
    PORTD |= (1<<PD4);
25
    _delay_ms(500);
26
    PORTD &= ~(1<<PD4);
27
    _delay_ms(500);
28
  }
29
  
30
  while(1)
31
    {
32
        spiX_put('1'); // Send data
33
    spiX_wait(); // Wait for transmission finished
34
    val = spiX_get();
35
    
36
    if(val == '1')
37
    {
38
      PORTD |= (1<<PD4);
39
    }
40
    else
41
    {
42
      PORTD &= ~(1<<PD4);
43
    }
44
    }
45
}

Ich lasse eine LED in der Interrupt-Routine des Timers blinken, um zu 
sehen ob er da überhaupt irgendwie reinkommt. Ich weiß, das hält den 
nächsten Interrupt auf und versaut das Timing, aber es ging erstmal nur 
darum zu sehen ob etwas passiert. Die LED macht aber gar nichts (außer 
am Anfang nach der Initialisierung).

von H.Joachim S. (crazyhorse)


Lesenswert?

TIMSK?

von Jens K. (mister232)


Lesenswert?

Wurde in spiX_put() realisiert und außerdem im Overflow-Interrupt der 
USI-Schnittstelle

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Jens K. schrieb:
> // Enable 'Clear Timer on Compare match' and init prescaler.
>   TCCR0A |= (1<<WGM01) | (1<<WGM00);

 Das ist kein Compare match, sondern Fast PWM.

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.