Forum: Mikrocontroller und Digitale Elektronik ATMega328P - Hardware SPI - SCK hoert nach ein paar Durchlaeufen auf zu wackeln


von Avr N. (balze)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich wollte mir "nur mal eben schnell" mit einem µC eine Moeglichkeit 
aufbauen, um die Kennlinie eines NTCs zu ermitteln.

Dazu habe ich den NTC in der wie von mir gewuenschten Weise an einen 
Analogeingang des ATMega328P angeschlossen und mir einen digitalen 
Temperatursensor besorgt (TI LM95071).
Beide Messwerte werden dann per serieller Kommunikation an ein FTDI 
Modul uebergeben, das die Daten am USB Port eines PCs zur Verfuegung 
stellt.

Alle 10ms wird der Analogwert gelesen und ein Mittelwert ueber 16 
Messungen gebildet. Ich bekomme also alle ~160ms einen Messwert.

Flux das alte Testboard umgebaut und los geht's.

Funktioniert soweit, bis auf das Hardware SPI. :(
(Deaktiviere ich das SPI_MasterReceive() funktioniert es und ich bekomme 
den gemittelten Analogwert alle 160ms.)

Ich habe fuer den TI-Sensor Hardware SPI des 328P verwendet.
Leider klappt das nicht wie erwartet.

Die ersten 10 bis 15 SPI Zyklen (jeweils 2 Byte) klappen problemlos. 
Doch dann geht SCK zwischen zwei Übertragungen auf high und bleibt dort.

Am SCK-Pin (PB5) ist nur der ISP Konnektor angeschlossen. Dieser dient 
entweder zum Anschluss des AVRISP MKII oder des TI Sensors.

Der Effekt tritt allerdings auch auf, wenn nix (also kein Sensor und 
natuerlich kein AVRISP) angeschlossen ist. (Es liegt also nicht (!) am 
TI Sensor.)

Kann mir jemand sagen, was ich uebersehen habe ?!

Ich wuerde mich sehr freuen.

Ich hoffe der Code ist nicht zuuuu lang um ihn im thread anzuzeigen.

Vielen Dank,

Balze aka AVR_Noob

P.S.: Auf den Screenshots ist zu sehen:
1. Zwoelf erfolgreiche UEbertragungen nach Einschalten
2. Fehlverhalten von SCK nach der 12ten UEbertragung
3. Zwoelfte UEbertragung im Detail

main.c:
1
/* define CPU frequency in Mhz here if not defined in Makefile */
2
#ifndef F_CPU
3
#define F_CPU 6000000UL // Externer Takt von dem FTDI FT232R Module (6Mz)
4
#endif
5
6
#include <util/delay.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <avr/io.h>
10
#include <inttypes.h>
11
#include <avr/interrupt.h>
12
#include <avr/pgmspace.h>
13
14
#include "peter_fleury_usart\uart.h"
15
#include "spi.h"
16
#include "adc.h"
17
18
#define UART_BAUD_RATE      125000
19
20
#define CS_DDR  DDRC      // Chip Select fuer TI Temp Sensor
21
#define CS_PORT PORTC
22
#define P_CS  PORTC4
23
24
25
volatile uint32_t Zehn_Millisekunden = 0;
26
27
volatile uint32_t Mittelwert_ADC = 0;
28
29
volatile uint8_t Mittelwert_Zaehler = 0;
30
31
volatile uint8_t diesen_Mittelwert_ignorieren = 1;
32
33
volatile uint16_t Messungs_Zaehler = 0;
34
35
volatile uint16_t Messwerte[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
36
37
volatile char rs232_array[7] = {'_','_','_','_','_','_',0};
38
39
40
ISR(TIMER1_COMPB_vect)
41
{
42
  Zehn_Millisekunden ++;
43
}
44
45
ISR(ADC_vect)
46
{  
47
  uint16_t alter_Wert = Messwerte[Mittelwert_Zaehler];
48
  uint16_t neuer_Wert =  ADC;
49
  Messwerte[Mittelwert_Zaehler] = neuer_Wert;
50
  Mittelwert_Zaehler++;
51
  Mittelwert_ADC = Mittelwert_ADC + (uint32_t) neuer_Wert - (uint32_t) alter_Wert;
52
  if (Mittelwert_Zaehler >= 16)
53
  {
54
    Mittelwert_Zaehler = 0;
55
    if (diesen_Mittelwert_ignorieren)    // Der erste Mittelwert wird entsorgt !
56
    {
57
      diesen_Mittelwert_ignorieren = 0;
58
    }
59
    else                  // Zweiter und folgender Mittelwert
60
    {
61
      rs232_array[0] = (uint8_t) (Mittelwert_ADC>>12);  // >> 12 -> Division durch 16 entspricht schieben um 4
62
                          // schieben um 8 fuer das hoeherwertige Byte
63
      rs232_array[1] = (uint8_t) (Mittelwert_ADC>>4);
64
      CS_PORT &= ~(1<<P_CS);          // Chip Select auf low
65
      _delay_us(1);
66
      rs232_array[2] = SPI_MasterReceive();
67
      _delay_us(1);
68
      rs232_array[3] = SPI_MasterReceive();
69
      _delay_us(1);
70
      CS_PORT |= (1<<P_CS);          // Chip Select auf high
71
      _delay_ms(1);
72
      rs232_array[4] = (uint8_t) (Messungs_Zaehler>>8);
73
      rs232_array[5] = (uint8_t) (Messungs_Zaehler++);
74
      for (int i=0;i<7;i++)
75
        uart_putc(rs232_array[i]);
76
    }
77
  }
78
}
79
80
int main ()
81
{
82
  CS_DDR |=  (1<<P_CS),
83
  CS_PORT |= (1<<P_CS);
84
85
  TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);
86
  TIMSK1 = (1<<OCIE1B);//(1<<OCIE1A) | (1<<OCIE1B);
87
  
88
  OCR1A = 937; // 937 fuer ~10 ms
89
  OCR1B = 937; // 937 fuer ~10 ms // OCR1B fuer das Triggern des ADCs
90
  TCNT1 = 0x00;
91
92
  uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
93
  init_ADC();
94
  SPI_MasterInit();
95
96
  sei();
97
98
  for (;;)
99
  {
100
  }
101
}

SPI.c:
1
#include <avr/io.h>
2
#include "spi.h"
3
4
#define SPI_DDR  DDRB
5
#define P_MOSI  PORTB3
6
#define P_MISO  PORTB4
7
#define P_SCLK  PORTB5
8
9
10
void SPI_MasterInit(void)
11
{
12
  /* Set MOSI and SCK output, all others input */
13
  SPI_DDR = (1<<P_MOSI ) | (1<<P_SCLK);
14
  /* Enable SPI, Master, set clock rate fck/16, SPI Mode 1 */
15
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPHA);// | (1<<SPR0) | (1<<SPR1);
16
}
17
18
char SPI_MasterReceive()
19
{
20
  uint32_t counter = 0;
21
  /* Start transmission */
22
  SPDR = 0x00;
23
  /* Wait for transmission complete */
24
  while(!(SPSR & (1<<SPIF)))
25
  ;
26
  return SPDR;
27
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Die Programmstruktur ist Murks.
Man macht sowas nicht im Interrupt:   while(!(SPSR & (1<<SPIF)));

Und überhaupt ist viel zu viel im Interrupt und viel zu wenig in der 
Hautpschleife. Warum heißt die Hauptschleife eigentlich 
Hauptschleife?

von Karlheinz (Gast)


Lesenswert?

Hallo,

entrümple deine ISR mal ganz schnell.

ISR sind gedacht um mal schnell auf einen Event zu reagieren.
Du hast daraus das Hauptprogramm gemacht!

von Avr N. (balze)


Lesenswert?

Da habt Ihr natuerlich beide Recht.

Aber sollte das Entruempeln wirklich mein komisches Problem loesen.

Zwischen "kein guter Stil" und "geht so nicht" ist ja noch ein 
Unterschied.

Danke erstmal, werde das nachher mal umstricken und ausprobieren ob das 
ursaechlich war.

Danke, mfG

Balze aka AVR-Noob

von Peter D. (peda)


Lesenswert?

Avr Noob schrieb:
> Doch dann geht SCK zwischen zwei Übertragungen auf high und bleibt dort.

Vermutlich der SPI-Standardfehler, wie hast Du den /SS Pin beschaltet 
bzw. definiert?


Peter

von Avr N. (balze)


Lesenswert?

Aeeeeehhhmm,

gar nicht :(

Ich habe vermutet, dass es egal ist welchen Pin ich fuer Chip(Slave) 
Select nehme.
(Ich sollte aufhoeren bei µCs Vermutungen anzustellen :)

Muss ich !SS behandeln als waere !SS der zustaendige Slave Select?
(als Ausgang definieren; low vor UEbertragung, high nach UEbertragung)

Danke, mfG

Balze aka AVR_Noob

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Avr Noob schrieb:
> (Ich sollte aufhoeren bei µCs Vermutungen anzustellen :)
Ja, dagegen hilft das Datenblatt...
1
When the SPI is configured as a Master (MSTR in SPCR is set), the user can
2
determine the direction of the SS pin.
3
4
If SS is configured as an output, the pin is a general output pin which 
5
does not affect the SPI system. Typically, the pin will be driving the 
6
SS pin of the SPI Slave.
7
8
If SS is configured as an input, it must be held high to ensure Master SPI 
9
operation. If the SS pin is driven low by peripheral circuitry when the SPI 
10
is configured as a Master with the SS pin defined as an input ... the SPI 
11
system takes the following actions:
12
1. The MSTR bit in SPCR is cleared and the SPI system becomes a Slave.

von Avr N. (balze)


Lesenswert?

Asche auf mein Haupt.

Ich muss gestehen, dass ich den Absatz "/SS Pin Functionality" komplett 
ueberlesen habe.

Sorry, dass ich Euch mit Anfaegnerfehlern dieZeit raube.

Dickes Danke!

Wird gleich ausprobiert (und hoffentlich in meinem nicht fluechtigen 
Speicher zwischen den Ohren abgelegt.)

MfG,

Balze aka AVR_Noob

von Avr N. (balze)


Lesenswert?

Kurze Rueckmeldung, damit moeglicherweise jemand anderes mit einem 
aehnlichen Problem nachlesen kann, dass Peter Danneggers Frage und 
Lothar Millers Hinweis auf das Datenblatt die Loesung gebracht haben.

Es funktioniert!

Vielen Dank nochmal!

MfG,

Balze aka AVR_Noob

von Stefan (Gast)


Lesenswert?

Den gleichen Fehler hatte ich auch gemacht, schätze darauf fallen viele 
Anfäger rein.

Auch AVR's verhalten sich nicht zu 100% so, wie man es vermutet. Man 
soll sich halt nicht auf Annahmen 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.