-
        

Ergebnis 1 bis 3 von 3

Thema: Hilfe bei Kommunikation über ISP-Schnittstelle

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.08.2006
    Ort
    Würzburg, Germany
    Beiträge
    672

    Hilfe bei Kommunikation über ISP-Schnittstelle

    Anzeige

    Hallo,

    ich bin an der Entwicklung eines Programms für einen Tiny25. Ich bentöige dabei Werte, die ich über den integrierten ADC einlese irgendwo angezeigt. Da der Tiny25 so wenige Pins hat habe ich mir überlegt diese Werte über die ISP-Schnittstelle zu senden, da ich diese eh "onboard" habe um den Controller darüber zu programmieren.

    Meine Idee war es also einen kleinen Umsetzer zu bauen, der mir die ISP-Daten auf eine serielel Schnittstelle übersetzt und umgekehrt. Für dieses Projekt habe ich einen Tiny2313 verwendet, da der noch rumlag. Die ISP-Schnittstelle ist ebenfalls so verdrahtet, dass ich den Tiny2313 darüber programmieren kann mit der Ausnahme das ich die Reset-Leitung per Jumper trennen kann und die Reset-Leitung von "außen" auf einen Eingangspin geht, damit ich die ISP-Schnittstelle abschalten kann solange der Tiny25 programmiert wird. Wenn also der externe Reset auf Low geht möchte ich die ISP-Schnittstelle abschalten.

    Leider ist aus den Datenblättern für mich nicht so ganz ersichtlich wie ich das ganze programmieren soll. Den Umsetzer mit dem Tiny2313 habe ich mir als ISP-Slave gedacht. Hier mal mein Code dafür:

    Code:
    #define AVRGCC/**
    ISP_RS232:
    Interface um Daten zwischen ISP und RS232 zu übersetzen.
    IO:
    PB0  out   LED gelb (Daten RS232 vorhanden)
    PB1  out   LED grün (Daten ISP vorhanden)
    PB2  frei
    PB3  frei
    PB4  frei
    PB5  MOSI
    PB6  MISO
    PB7  SCK
    PD0  RXD
    PD1  TXD
    PD2  in   disable (ext. Reset)
    PD3  frei
    PD4  frei
    PD5  frei
    PD6  Out   LED rot (Buffer Überlauf)
    **/
     
    #include <avr/io.h>
    #include <compiler.h>
    #include <avr/interrupt.h>
     
    //F_CPU = 8000000
    #define BAUD     9600l
    #define UBRRValue    (F_CPU / (BAUD * 16) - 1)
    #define BufferSize    16
    #define LED_ge_0    PORTB = ~(~PORTB | (1<<PB0))
    #define LED_ge_1    PORTB = (PORTB | (1<<PB0))
    #define LED_gn_0    PORTB = ~(~PORTB | (1<<PB1))
    #define LED_gn_1    PORTB = (PORTB | (1<<PB1))
    #define LED_rt_0    PORTD = ~(~PORTD | (1<<PD6))
    #define LED_rt_1    PORTD = (PORTD | (1<<PD6))
    #define disable     ((PIND & 1<<PD2) == 0)
    #define RS232ready    ((UCSRA & (1<<UDRE)) != 0)
    #define AccessRead    0
    #define AccessWrite    1
    #define BufferRS232    0
    #define BufferISP    1
     
    volatile bool currentState = FALSE;
    volatile U8  InBuffer[2][BufferSize];
    volatile U8  Pointer[2][2];
     
    
    void sendMsg (char *Msg, bool addCR)
    {
     while (*Msg != 0)
     {
      while ( !(UCSRA & (1<<UDRE)));
      UDR = *Msg++;
     }
     if (addCR)
      sendMsg ("\r\n", FALSE);
    }
     
    void incPointer (U8 Buffer, U8 Access)
    {
     if (++Pointer[Buffer][Access] >= BufferSize)
      Pointer[Buffer][Access] = 0;
    }
    bool BufferDone (U8 Buffer)
    {
     return (Pointer[Buffer][AccessRead] == Pointer[Buffer][AccessWrite]);
    }
    void add2Buffer (U8 Buffer, U8 value)
    {
     U8 tmp = Pointer[Buffer][AccessWrite];
     if (++tmp >= BufferSize)
      tmp = 0;
     
     if (tmp != Pointer[Buffer][AccessRead])
     {
      Pointer[Buffer][AccessWrite] = tmp;
      InBuffer[Buffer][tmp] = value;
     }
     else
      LED_rt_1;
    }
    U8 readBuffer (U8 Buffer)
    {
     return (InBuffer[Buffer][AccessRead]);
    }
     
    ISR (USART_RX_vect)
    {
     add2Buffer (BufferRS232, UDR);
    }
     
    ISR (USI_OVERFLOW_vect)
    {
     U8 value = USIDR;
     if (currentState)
     {
      add2Buffer (BufferISP, value);
      if (!BufferDone (BufferRS232))
       incPointer (BufferRS232, AccessRead);
      if (!BufferDone (BufferRS232))
       USIDR = readBuffer (BufferRS232);
      else
       USIDR = 0;
     }
     else
      LED_rt_1;
    }
     
    int main (void)
    {
     DDRB =  0b00000011;
     PORTB = 0b00000000;
     
     DDRD =  0b01000000;
     PORTD = 0b00000000;
     UCSRB = (1<<RXCIE) | (1<<TXEN) | (1<<RXEN);
     UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
     UBRRH = (U8)(UBRRValue>>8);
     UBRRL = (U8)UBRRValue;
     Pointer[BufferRS232][AccessRead] = 0;
     Pointer[BufferRS232][AccessWrite] = 0;
     Pointer[BufferISP][AccessRead] = 0;
     Pointer[BufferISP][AccessWrite] = 0;
     sei ();
     
     sendMsg ("", TRUE);
     sendMsg ("RESET", TRUE);
     
     while (1)
     {
      if (disable)
      {
       if (currentState)
       {
        USICR = 0;
        sendMsg ("TARGET RESET", TRUE);
       }
       currentState = FALSE;
      }
      else
      {
       if (!currentState)
       {
        USICR = (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) |(1<<USIOIE);
        sendMsg ("TARGET START", TRUE);
        if (!BufferDone (BufferRS232))
         USIDR = readBuffer (BufferRS232);
        else
         USIDR = 0;
       }
       currentState = TRUE;
      }
     
     
     
      if (RS232ready & !BufferDone (BufferISP))
      {
       UDR = readBuffer (BufferISP);
       incPointer (BufferISP, AccessRead);
      }
     
      if (BufferDone (BufferISP))
       LED_gn_0;
      else
       LED_gn_1;
      if (BufferDone (BufferRS232))
       LED_ge_0;
      else
       LED_ge_1;
     }
     
     return (0);
    }
    Die RS232-Kommunikation läuft. RESET wird gemeldet und TARGET RESET bzw. TARGET START wird auch gemeldet. Und wenn ich etwas sende geht die gelbe LED als Anzeige an, dass etwas im RS232-Buffer vorhanden ist. (Nach 16 Bytes geht dann auch die rote LED an)

    Der Tiny25 soll dann als ISP-Master funktionieren. Hier mal mein Test-Code um etwas zu senden:

    Code:
    #define AVRGCC
    /**
    Voltage Detector:
    
    IO:
    PB0  MOSI
    PB1  MISO out   LED
    PB2  SCK
    PB3  analog in (ADC3)
    PB4  frei
    **/
     
    #include <avr/io.h>
    #include <util/delay.h>
    #include <compiler.h>
     
    //F_CPU = 1000000
    #define LED0      PORTB = ~(~PORTB | (1<<PB1))
    #define LED1      PORTB = (PORTB | (1<<PB1))
     
    int get_analog_input (void)
    {
     ADCSRA |= (1<<ADSC);
     while ((ADCSRA & (1<<ADSC)) > 0);
     return ((ADCH<<8) | ADCL) - 512;
    }
     
    int main (void)
    {
     DDRB =  0b00000010;
     PORTB = 0b00000000;
     DIDR0 = (1<<ADC3D);
     ADMUX = (1<<REFS1) | (1<<REFS2) | (1<<MUX1) | (1<<MUX0);
     ADCSRA = (1<<ADEN);
     USICR = (1<<USIWM0);
    
    USIDR = 'A';
    U8 i1;
    for (i1 = 0; i1 < 8; i1++)
    {
     USICR |= (1<<USICLK);
     _delay_ms (1);
    }
    
     while (1);
    
     return (0);
    }
    Leider kommt beim Umsetzer nichts an (grüne LED bleibt aus). Wenn ich den Tiny25 programmiere erkennt der Umsetzer aber brav die Reset-Leitung und meldet "TARGET RESET" und "TARGET START".

    Wo könnte mein Problem liegen? Liegt es an der Verdrahtung? Kann ich vielleicht gar keine Kommunikation bei einer 1:1 verdrahteten ISP-Schnittstelle aufbauen? So wie ich das Verstehe müsste es gehen, da die Pins ja MISO (Master In Slave Out) und MOSI (Master Out und Slave In) heißen. Allerdings habe ich in der Beschreibung der Register für die USI-Schnittstelle nirgendwo gesehen wie ich Master und Slave konfiguriere.

    Viele Grüße
    Andreas

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.08.2006
    Ort
    Würzburg, Germany
    Beiträge
    672
    Guten Morgen,

    dieses Problem ist immer noch aktuell und benötigt eine Lösung. Da ich zur Zeit für andere Projekte auf Teile warte habe ich selbst noch mal etwas Zeit investiert und bin ein Stück weiter. Die erste Erkenntnis nach genauer Studie des Datenblattes ist, dass der Master den Takt für die ISP-Schnittstelle per Software selbst generieren muss. Das finde ich schade. Ich dachte ich schiebe mein Datenbyte ins USIDR Register und setze ein Flag "Start" und erhalte dann, wie von RS232 gewohnt, einen Interrupt sobald die Übertragung abgeschlossen ist.
    Aber vielleicht finde ich da noch eine Lösung. (Ich hoffe, dass ich das im Datenblatt noch übersehen habe)

    Auf jeden Fall habe ich den Tiny25 zum Master gemacht mit folgendem Code:
    Code:
    #define AVRGCC
    #include <avr/io.h>
    #include <util/delay.h>
    #include <compiler.h>
    //F_CPU = 1000000
    U8 ISP_send (U8 value)
    {
     USISR |= (1<<USIOIF);
     USICR = (1<<USIWM0) | (1<<USITC);
     USIDR = value;
     while ((USISR & (1<<USIOIF)) == 0)
     {
      USICR = (1<<USIWM0) | (1<<USITC) |(1<<USICLK);
      _delay_ms (100);
      USICR = (1<<USIWM0) | (1<<USITC);
      _delay_ms (100);
     }
     return (USIDR);
    }
    int main (void)
    {
     DDRB =  0b00000110;
     PORTB = 0b00000000;
     U8 value = 'A';
     while (1)
     { 
      ISP_send (value++);
      if (value > 'Z')
       value = 'A';
      _delay_ms (5000);
     }
     return (0);
    }
    Es wird mit sehr langsam Takt die Buchstaben des Alphabets mit jeweils 5 Sekunden Pause zwischen den Buchstaben gesendet, damit man die Bits quasi noch mal dem Auge verfolgen kann. Das scheint zu funktionieren, zumindest tut sich was auf den Datenleitungen. Hier mal ein Video:

    http://www.car-mp3.de/RNetz/ISP.zip

    Die grün LED ist der Takt und gelb die Daten. Die linke/obere Platine ist der Master mit dem Tiny25. Rechts/unten ist das ISP/RS232-Interface mit dem Tiny2313 als Slave. Hier der Code für das Interface:

    Code:
    #define AVRGCC
    #include <avr/io.h>
    #include <compiler.h>
    #include <avr/interrupt.h>
    //F_CPU = 8000000
    #define BAUD     9600L
    #define UBRRValue    (F_CPU / (BAUD * 16) - 1)
    #define LED_ge_0    PORTB = ~(~PORTB | (1<<PB0))
    #define LED_ge_1    PORTB = (PORTB | (1<<PB0))
    #define LED_gn_0    PORTB = ~(~PORTB | (1<<PB1))
    #define LED_gn_1    PORTB = (PORTB | (1<<PB1))
    #define RS232ready    ((UCSRA & (1<<UDRE)) != 0)
    void sendNumber (U32 Number, bool addCR)
    {
     if (Number == 0)
     {
      while ( !(UCSRA & (1<<UDRE)));
      UDR = '0';
     }
     else
     {
      U32  ZifferGrundWert = 1000000000;
      bool ZifferWert;
      bool started = FALSE;
    
      while ((Number > 0) | (started & (ZifferGrundWert > 0)))
      {
       if (ZifferGrundWert == 1)
       {
        ZifferGrundWert = 0;
        ZifferWert = Number;
        Number = 0;
       }
       else
       {
        ZifferWert = 0;
       
        while (Number >= ZifferGrundWert)
        {
         Number = Number - ZifferGrundWert;
         ZifferWert++;
        }
        ZifferGrundWert = ZifferGrundWert / 10;
       }
     
       while ( !(UCSRA & (1<<UDRE)));
       if ((ZifferWert > 0) | started)
       {
        UDR = '0' + ZifferWert;
        started = TRUE;
       }
       else
       {
        if (started)
         UDR = '0';
       }
      }
     }
     if (addCR)
      sendMsg ("\r\n", FALSE);
    }
    ISR (USI_OVERFLOW_vect)
    {
     USISR |= (1<<USIOIF);
     sendNumber (USIDR, TRUE);
    }
    int main (void)
    {
     DDRB =  0b00000011;  // Alternativ: DDRB =  0b00100011; Richtig müsste es eigentlich 0b01000011 sein
     PORTB = 0b00000000;
     
     DDRD =  0b01000000;
     PORTD = 0b00000000;
     UCSRB = (1<<RXCIE) | (1<<TXEN) | (1<<RXEN);
     UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
     UBRRH = (U8)(UBRRValue>>8);
     UBRRL = (U8)UBRRValue;
     USISR |= (1<<USIOIF);
     USICR = (1<<USIWM0) | (1<<USICS1) | (1<<USIOIE);
     sei ();
     while (1)
     {
      if ((PINB & 1<<PB7) == 0)
       LED_gn_0;
      else
       LED_gn_1;
      if ((PINB & 1<<PB6) == 0)
       LED_ge_0;
      else
       LED_ge_1;
     }
     return (0);
    }
    Wie man sieht werden die Leds im Code geschaltet und hängen nicht direkt an den Datenleitungen. Es kommt also was am Slave an. Und wenn der Master das Datenbyte übertragen hat wird auch der USI_OVERFLOW_vect Interrupt ausgelöst. Die ISP-Initialisierung ist zumindest teilweise korrekt. Nur leider ist der empfangene Datenwert immer 255. Wenn ich die Alternative DDRB Initialisierung, wie im Code kommentiert verwende empfange ich immer als Datenwert 0.

    Es scheint so, als ob die Datenleitungen noch vertauscht werden müssen. Das zeigt auch die Initialisierung von DDRB. Normalerweise müsste es ja 0b01000011 heißen. Dann bleibt aber die gelbe LED dunkel und die beiden Atmels kämpfen mit ihren Ausgängen "gegeneinander".
    Ich habe es im Datenblatt leider nicht gefunden: Kann man die ISP-Schnittstelle so konfigurieren, dass die Pins als ISP-Slave verwendet werden? Also MOSI und MISO vertauscht? Müsste ja eigentlich gehen, da die Leitungen ja schon so heißen und man einfach 1:1 durchverdrahten kann.

    Viele Grüße
    Andreas

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.08.2006
    Ort
    Würzburg, Germany
    Beiträge
    672
    So, ich beende meinen Monolog. Das Problem ist gelöst. Nach längerem Googeln habe ich herausgefunden, dass der Tiny25 nicht als SPI-Master verwendet werden kann, zumindest nicht mit den integrierten Funktionen des Schieberegisters.
    Man muss das Schiebe-Register selbst im Code nachbilden. Damit läuft es nun.

    Viele Grüße
    Andreas

Ähnliche Themen

  1. Antworten: 3
    Letzter Beitrag: 25.11.2012, 20:56
  2. Brauche Hilfe bei der Kommunikation zweier Atmega über UART
    Von gm4288 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 27.12.2011, 22:47
  3. Kommunikation über usb Schnittstelle mega2560 und linux
    Von what? im Forum PC-, Pocket PC, Tablet PC, Smartphone oder Notebook
    Antworten: 9
    Letzter Beitrag: 22.01.2009, 09:40
  4. Antworten: 0
    Letzter Beitrag: 11.09.2005, 19:06
  5. RS232-Ersatz: Datenübertragung über die ISP-Schnittstelle
    Von talentraspel_kai im Forum AVR Hardwarethemen
    Antworten: 0
    Letzter Beitrag: 30.12.2004, 17:55

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •