Forum: Mikrocontroller und Digitale Elektronik 16 Bit SPI senden


von Tobi W. (Gast)


Lesenswert?

Hallo,

ich möchte mit einem atmega8 16 Bit mithilfe der SPI Hardware an einen 
MPC 4921 DAC senden.

Datenblatt: 
http://www.reichelt.de/?;ACTION=7;LA=28;OPEN=0;INDEX=0;FILENAME=A200%252FMCP4921_MCP4922_MIC.pdf;SID=32Y2QSRawQASAAAGETf-08bce0255a2066c93b1cc58e240af89af

Den DAC konnte ich bereits per Software ansteuern, leider funktioniert 
es mit der Hardware nicht.

Den CS (low aktiv)  habe ich auf Pin B0 gesetzt. Dieser wird vorm senden 
des 1. Byte auf low gesetzt, nachdem das 2. Byte gesendet ist wieder auf 
high.

Ein globales statusbyte gibt an ob der spi bus frei ist oder ob gerade 
das 1. oder 2. byte geschickt wird.

Ein Interrupt wird ausgelöst, wenn ein Byte verschickt wurde, je nachdem 
in welchem Status er sich befindet wird das 2. Byte verschickt oder der 
SPD Bus im Status freigegeben. Leider funktioniert der Code nicht.


(Der ADC erwartet 4 Controlbits (0111), danach 12 Bit für den DAC. Die 
12 sind die 12 höchsten Bit eines zeichenlosen 16 Bit Wortes. Bei der 
Hardware Version soll ein weiteres verschicken eines 16 Bit Wortes 
einfach ignoriert werden. In der Main Funktion wird in einer 
Endlosschleife 65535 versendet)

main:
1
#include <avr/io.h> 
2
#include "mcp_4921.h"
3
4
5
int main(void) 
6
{  
7
    mcp_init();
8
  while(1)
9
  {
10
    mcp_setValue(65535);
11
  }
12
  return 0;
13
}

mcp_4921.h:
1
#ifndef MODUL_MCP_4921_H
2
#define MODUL_MCP_4921_H
3
4
#include <avr/io.h>
5
6
7
8
#define SCK    5
9
#define SDI    3
10
#define CS    0
11
#define LDAC  1
12
13
#define DDR_SPI DDRB
14
#define PORT_SPI PORTB
15
16
17
void mcp_setValue(uint16_t value);
18
void mcp_init(void);
19
20
volatile int8_t spi_status;
21
uint8_t lower_byte;
22
23
#endif

mcp4921.c in Software (funktioniert):
1
#include "mcp_4921.h"
2
#include <avr/io.h>
3
4
void mcp_init(void)
5
{
6
  DDR_SPI |= (1<<CS)|(1<<SCK)|(1<<SDI)|(1<<LDAC);  // Setzte Busausgänge
7
  
8
  PORT_SPI |= (1<<CS)|(1<<LDAC);          // MPC ist nicht für SPI aktiv
9
  PORT_SPI &=~ (1<<SCK);              // Setzt clock-Flanke auf low
10
}
11
12
13
void mcp_setValue(uint16_t value)
14
{
15
  int8_t i;
16
  
17
  PORT_SPI &=~ (1<<CS);  // Wähle DAC als SPI Empfänger aus
18
  
19
  PORT_SPI &=~ (1<<SDI);  // Wähle ADC_A
20
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
21
  
22
  PORT_SPI |= (1<<SDI);  // Die andereren 3 Config Bits sind High
23
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
24
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
25
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
26
  
27
  for(i=0;i<12;i++)
28
  {
29
    if(value&(1<<(15-i))) 
30
    {
31
      PORT_SPI |= (1<<SDI);
32
    }
33
    else
34
    {
35
      PORT_SPI &=~ (1<<SDI);
36
    }
37
    PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
38
  }
39
40
  PORT_SPI |= (1<<CS);  // DAC als SPI Empfänger deaktivieren
41
  PORT_SPI &=~ (1<<LDAC);
42
  PORT_SPI |= (1<<LDAC);
43
}

und mcp4921.c in Hardware (funktioniert nicht):
1
#include "mcp_4921.h"
2
#include <avr/io.h>
3
#include <avr/interrupt.h> 
4
5
6
ISR(SPI_STC_vect)       /* SPI Transfer Complete Handler */
7
{
8
    switch(spi_status)
9
  {
10
  case 1:
11
    /* 1. Byte wurde gesendet */
12
    SPDR = lower_byte;       // Sende 2. Byte
13
    spi_status = 2;        // Status: 2. Byte wird an ADC gesendet
14
    break;
15
  case 2:
16
    /* 1. Byte wurde gesendet */
17
    PORT_SPI |= (1<<CS);    // Deaktiviere mpc als SPI Empfänger
18
    PORT_SPI &=~ (1<<LDAC);   // Lade ADC Wert
19
    PORT_SPI |= (1<<LDAC);
20
    spi_status = 0;        // SPI frei
21
    break;
22
  }
23
}
24
25
26
void mcp_init(void)
27
{
28
  DDR_SPI = (1<<CS)|(1<<SCK)|(1<<SDI)|(1<<LDAC);  // Setzte Busausgänge
29
  SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR);        // SPI Interruppt Enable, Enable SPI, Master, set clock rate fck/4
30
  spi_status = 0;                    // SPI frei
31
  sei();
32
}
33
34
void mcp_setValue(uint16_t value)
35
{
36
  
37
  if(spi_status==0)
38
  {
39
    PORT_SPI &=~ (1<<CS);        // Wähle DAC als SPI Empfänger aus
40
    spi_status = 1;            // Status: 1. Byte wird an ADC gesendet
41
    lower_byte = (uint8_t) (value>>4);  // Merke dir niederwertiges Byte (Die höchsten 12 Bit werden versendet)
42
    SPDR = 0b01110000|(value>>12);    // Setze Controlbits '0111', verschiebe die 4 höchsten Bits an die richtige Stelle und starte SPI senden
43
     
44
  }
45
  
46
}

Wäre sehr dankbar wenn mir jemand helfen kann.

Gruß

Tobi

von Tobi W. (Gast)


Lesenswert?

"Bei der Hardware Version soll ein weiteres verschicken eines 16 Bit 
Wortes
einfach ignoriert werden."

Soll natürlich heißen:

"Bei der Hardware Version soll ein weiteres verschicken eines 16 Bit 
Wortes
einfach ignoriert werden, solange der SPI nicht wieder frei ist."

von Stefan P. (form)


Lesenswert?

1
SPDR = 0b01110000|(value>>12); // Setze Controlbits '0111', verschiebe die 4 höchsten Bits an die richtige Stelle und starte SPI senden
2
while(!(SPSR & (1<<SPIF))); // Warten bis SPI fertig ist

von Peter (Gast)


Lesenswert?

Gucke Dir den SPI-Transfer mal mit dem Oszilloskop und vergleiche die 
beiden Varianten. Was ist anderst? Das sicher bei der Fehlersuche...

von Tobi W. (Gast)


Lesenswert?

Es funktioniert jetzt. Ich habe den LDAC jetzt auf Masse gelegt. Daran 
kann es aber nicht gelegen haben...

wie auch immer, so funktionierts:
1
ISR(SPI_STC_vect)       /* SPI Transfer Complete Handler */
2
{
3
    switch(spi_status)
4
  {
5
  case 1:
6
    /* 1. Byte wurde gesendet */
7
    SPDR = lower_byte;       // Sende 2. Byte
8
    spi_status = 2;        // Status: 2. Byte wird an ADC gesendet
9
    break;
10
  case 2:
11
    /* 1. Byte wurde gesendet */
12
    PORT_SPI |= (1<<CS);    // Deaktiviere mcp als SPI Empfänger
13
    spi_status = 0;        // SPI frei
14
    break;
15
  }
16
}
17
18
19
void mcp_init(void)
20
{
21
  DDR_SPI = (1<<CS)|(1<<SCK)|(1<<SDI);  // Setzte Busausgänge
22
  SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR);        // SPI Interruppt Enable, Enable SPI, Master, set clock rate fck/4
23
  SPSR = (1<<SPI2X);                  // Double Speed
24
  spi_status = 0;                    // SPI frei
25
  sei();
26
}
27
28
void mcp_setValue(uint16_t value)
29
{
30
  
31
  if(spi_status==0)
32
  {
33
    PORT_SPI &=~ (1<<CS);        // Wähle DAC als SPI Empfänger aus
34
    spi_status = 1;            // Status: 1. Byte wird an DAC gesendet
35
    lower_byte = (uint8_t) (value>>4);  // Merke dir niederwertiges Byte (Die höchsten 12 Bit werden versendet)
36
    SPDR = 0b01110000|(value>>12);    // Setze Controlbits '0111', verschiebe die 4 höchsten Bits an die richtige Stelle und starte SPI senden
37
     
38
  }
39
  
40
}

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.