www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 16 Bit SPI senden


Autor: Tobi W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;IND...

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:
#include <avr/io.h> 
#include "mcp_4921.h"


int main(void) 
{  
    mcp_init();
  while(1)
  {
    mcp_setValue(65535);
  }
  return 0;
}

mcp_4921.h:
#ifndef MODUL_MCP_4921_H
#define MODUL_MCP_4921_H

#include <avr/io.h>



#define SCK    5
#define SDI    3
#define CS    0
#define LDAC  1

#define DDR_SPI DDRB
#define PORT_SPI PORTB


void mcp_setValue(uint16_t value);
void mcp_init(void);

volatile int8_t spi_status;
uint8_t lower_byte;

#endif

mcp4921.c in Software (funktioniert):
#include "mcp_4921.h"
#include <avr/io.h>

void mcp_init(void)
{
  DDR_SPI |= (1<<CS)|(1<<SCK)|(1<<SDI)|(1<<LDAC);  // Setzte Busausgänge
  
  PORT_SPI |= (1<<CS)|(1<<LDAC);          // MPC ist nicht für SPI aktiv
  PORT_SPI &=~ (1<<SCK);              // Setzt clock-Flanke auf low
}


void mcp_setValue(uint16_t value)
{
  int8_t i;
  
  PORT_SPI &=~ (1<<CS);  // Wähle DAC als SPI Empfänger aus
  
  PORT_SPI &=~ (1<<SDI);  // Wähle ADC_A
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
  
  PORT_SPI |= (1<<SDI);  // Die andereren 3 Config Bits sind High
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
  PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
  
  for(i=0;i<12;i++)
  {
    if(value&(1<<(15-i))) 
    {
      PORT_SPI |= (1<<SDI);
    }
    else
    {
      PORT_SPI &=~ (1<<SDI);
    }
    PORT_SPI |= (1<<SCK); PORT_SPI &=~ (1<<SCK); // Takt
  }

  PORT_SPI |= (1<<CS);  // DAC als SPI Empfänger deaktivieren
  PORT_SPI &=~ (1<<LDAC);
  PORT_SPI |= (1<<LDAC);
}

und mcp4921.c in Hardware (funktioniert nicht):
#include "mcp_4921.h"
#include <avr/io.h>
#include <avr/interrupt.h> 


ISR(SPI_STC_vect)       /* SPI Transfer Complete Handler */
{
    switch(spi_status)
  {
  case 1:
    /* 1. Byte wurde gesendet */
    SPDR = lower_byte;       // Sende 2. Byte
    spi_status = 2;        // Status: 2. Byte wird an ADC gesendet
    break;
  case 2:
    /* 1. Byte wurde gesendet */
    PORT_SPI |= (1<<CS);    // Deaktiviere mpc als SPI Empfänger
    PORT_SPI &=~ (1<<LDAC);   // Lade ADC Wert
    PORT_SPI |= (1<<LDAC);
    spi_status = 0;        // SPI frei
    break;
  }
}


void mcp_init(void)
{
  DDR_SPI = (1<<CS)|(1<<SCK)|(1<<SDI)|(1<<LDAC);  // Setzte Busausgänge
  SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR);        // SPI Interruppt Enable, Enable SPI, Master, set clock rate fck/4
  spi_status = 0;                    // SPI frei
  sei();
}

void mcp_setValue(uint16_t value)
{
  
  if(spi_status==0)
  {
    PORT_SPI &=~ (1<<CS);        // Wähle DAC als SPI Empfänger aus
    spi_status = 1;            // Status: 1. Byte wird an ADC gesendet
    lower_byte = (uint8_t) (value>>4);  // Merke dir niederwertiges Byte (Die höchsten 12 Bit werden versendet)
    SPDR = 0b01110000|(value>>12);    // Setze Controlbits '0111', verschiebe die 4 höchsten Bits an die richtige Stelle und starte SPI senden
     
  }
  
}

Wäre sehr dankbar wenn mir jemand helfen kann.

Gruß

Tobi

Autor: Tobi W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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."

Autor: Stefan P. (form)
Datum:

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

Autor: Peter (Gast)
Datum:

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

Autor: Tobi W. (Gast)
Datum:

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

wie auch immer, so funktionierts:
ISR(SPI_STC_vect)       /* SPI Transfer Complete Handler */
{
    switch(spi_status)
  {
  case 1:
    /* 1. Byte wurde gesendet */
    SPDR = lower_byte;       // Sende 2. Byte
    spi_status = 2;        // Status: 2. Byte wird an ADC gesendet
    break;
  case 2:
    /* 1. Byte wurde gesendet */
    PORT_SPI |= (1<<CS);    // Deaktiviere mcp als SPI Empfänger
    spi_status = 0;        // SPI frei
    break;
  }
}


void mcp_init(void)
{
  DDR_SPI = (1<<CS)|(1<<SCK)|(1<<SDI);  // Setzte Busausgänge
  SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR);        // SPI Interruppt Enable, Enable SPI, Master, set clock rate fck/4
  SPSR = (1<<SPI2X);                  // Double Speed
  spi_status = 0;                    // SPI frei
  sei();
}

void mcp_setValue(uint16_t value)
{
  
  if(spi_status==0)
  {
    PORT_SPI &=~ (1<<CS);        // Wähle DAC als SPI Empfänger aus
    spi_status = 1;            // Status: 1. Byte wird an DAC gesendet
    lower_byte = (uint8_t) (value>>4);  // Merke dir niederwertiges Byte (Die höchsten 12 Bit werden versendet)
    SPDR = 0b01110000|(value>>12);    // Setze Controlbits '0111', verschiebe die 4 höchsten Bits an die richtige Stelle und starte SPI senden
     
  }
  
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.