Re: Atmel AVR, SPI a C

Můžu tě poprosit o zběžnou kontrolu kódu? jestli je chyba tam, nebo mám chybu v HW, protože mi přijde, že MCU vždycky zatuhne, jelikož nemůže zapsat do CS8416.

/*
 * CS8416.c
 *
 * Created: 29.4.2012 16:21:53
 * Author: Dohnalik http://www.dohny.cz
 * Datasheet CS8416: http://www.cirrus.com/en/pubs/proDatasheet/CS8416_F3.pdf
 * 
 */ 

#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile uint8_t totalOverflow;
int set;

uint8_t SPI(uint8_t data){
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Počkej na dokončení přenosu.
    return SPDR;
}

uint8_t CS8416Read(uint8_t addr){
   PORTB &= ~(1<<PB2);
   _delay_us(1);
   
   SPI(0b00100000);  // Adresa čipu a Write bit.
   SPI(addr);   // Adresa registru, ze kterého chci číst.
   
   PORTB |= (1<<PB2); 
   _delay_us(1);
   PORTB &= ~(1<<PB2);
   _delay_us(1);
   
   SPI(0b00100001);  // Adresa čipu a Read bit.
   
   uint8_t data = SPI(0xFF);  // Čtu data.
        
   PORTB |= (1<<PB2); 
    
   return data;
}

void CS8416Write(uint8_t addr, uint8_t data){
    PORTB &= ~(1<<PB2);
    _delay_us(1);
    
    SPI(0b00100000); // Adresa čipu a Write bit.
    SPI(addr); // Adresa registru, do kterého chci zapisovat.
    SPI(data); //Zápis.
    
    PORTB |= (1<<PB2); 
}

ISR(TIMER0_OVF_vect){ // Metoda zavolána při přetečení timeru0.
    totalOverflow++;
}

void CS8416set(){
    uint8_t i;
    _delay_ms(20);
    PORTB |= (1<<PB1); // Reset log 1.
    _delay_ms(10);
    i = CS8416Read(0x05);
    i |= (1<<7)|(1<<2)|(1<<1); // Nastavení audio výstupu CS8416 na I2S master.
    CS8416Write(0x05, i); 
    i = CS8416Read(0x04);
    i |= (1<<7); // Příkaz RUN - normální operace.
    CS8416Write(0x04, i); 
    set++;
}

int main(void)
{
    DDRB |= (1<<DDB5)|(1<<DDB3)|(1<<DDB2)|(1<<DDB1); // Nastavení I/O pro SPI + reset.
    DDRD |= (1<<DDD3)|(1<<DDD4)|(1<<DDD5)|(1<<DDD6); // IN: PD1 - ON/OFF tlac.; PD2 - prepinani vstupu tlac.;
                                                     // OUT: PD3 - ON LED; PD4 - RX0 LED; PD5 - RX1 LED; PD6 - ERR LED
    PORTB &= ~(1<<PB1);    // Reset log 0.                                             
    SPCR |= (1<<SPE)|(1<<MSTR); // SPI zapnuto, Master, rychlost F_CPU/4.
    SPSR |= (1<<SPI2X); // SPI pracuje na dvojnásobné frekvenci (500 KHz).
    
    TCCR0B |= (1<<CS00); // Inicializace Timeru 0. No prescaler.
    TIMSK0 |= (1 << TOIE0); // Povolení přerušení.
    TCNT0 = 0; // Reset čítače.
    
    sei();
    
    totalOverflow = 0;
    
    uint16_t LED;
    long tlac;
    int zapnuti = 0;
    int predchoziStav = 0;
    int predchoziStav2 = 0;
    long cas;
    long cas2;
    uint8_t vstup = 0;
    uint8_t i;
    uint8_t n;
    int predchoziVstup = 1;
    int predchoziSampl = 1;
            
    while(1) // Loop, nečekaně.***********************************************
    {
        if (totalOverflow >= 3)
        {
            if (TCNT0 >= 232) 
            { // Přičte každou 1 ms.
                LED++; 
                tlac++;
                totalOverflow = 0;
                TCNT0 = 0;
            }
        }

        if (tlac >= 9223372036854775800){ // Ochrana proti přetečení long.
            tlac = 0;
            LED = 0;
        }            
        
        if(!(PIND & 1<<PD1) && predchoziStav == 0 && tlac - cas > 300){ // Zapnutí.
            if (zapnuti == 1)
                zapnuti = 0;
                
            else
                zapnuti = 1;
            
            cas = tlac;
        }
        predchoziStav = !(PIND & 1<<PD1);    
        
        if (zapnuti == 1){
            PORTD |= (1<<PD3);
            
            // Funkce po zapnutí. ********************************************************************************
            
            if(!(PIND & 1<<PD2) && predchoziStav2 == 0 && tlac - cas2 > 300){ // Přepínání vstupů.
                if (vstup == 1)
                vstup = 0;
                
                 else
                vstup = 1;
            
                cas2 = tlac;        
            }
            predchoziStav2 = !(PIND & 1<<PD2);
        
            if (set == 0){ // Po provedení se nastaví set na 1 - CS8416 se nastaví jen jednou.
            CS8416set();
            }
            if (vstup == 0 && predchoziVstup == 1){
                i = CS8416Read(0x04);
                i &= ~(1<<3);
                CS8416Write(0x04, i); // Nastaví vstup RX0.
                predchoziVstup = 0;
                PORTD |= (1<<PD4);
                PORTD &= ~(1<<PD5);
            } 
            else if (vstup == 1 && predchoziVstup == 0){
                i = CS8416Read(0x04);
                i |= (1<<3);
                CS8416Write(0x04, i); // Nastaví vstup RX1.
                predchoziVstup = 1;
                PORTD |= (1<<PD5);
                  PORTD &= ~(1<<PD4);
            }                
            i = CS8416Read(0x0B);            
            if (i & (1<<0) && predchoziSampl == 1){ // Pokud je samplovací frekvence menší než 88,1 KHz, nastaví PDUR.
                n = CS8416Read(0x00);
                n &= ~(1<<3);
                CS8416Write(0x00, n); 
                predchoziSampl = 0;
            } 
            else if (i & !(1<<0) && predchoziSampl == 0){
                n = CS8416Read(0x00);
                n |= (1<<3);
                CS8416Write(0x00, n);
                predchoziSampl = 1;
            }
            
            if (i & (1<<6)) { // Při detekci PCM dat bliká LED, jinak svítí.
                if (LED == 1000){
                    PORTD |= (1<<PD6);
                }
                else if (LED ==2000){
                    PORTD &= ~(1<<PD6);
                    LED = 0;
                }
            } 
            else{
                PORTD |= (1<<PD6);
            }
            
        }
            //****************************************************************************************************
        
        else{
            PORTB |= (1<<PB1); // Reset log1.
            PORTD = 0x00; // Zhasnutí LED.
            set = 0;
            LED = 0;
            i = CS8416Read(0x04);
            i &= ~(1<<7); // Příkaz !RUN - zastavení veškerých hodin a uspání CS8416...
            CS8416Write(0x04, i); 
            PORTB &= ~(1<<PB1); // Reset log 0 - vypnutí CS8416
        }
        
    }    
}

Re: Atmel AVR, SPI a C

jediny čeho jsem si všiml že nemáš inicializovanej int set = 0;  Jinak se v tom horko težko orientuje..je to psané poněkud zvláštně (rozuměj prasácky big_smile )..hlavně ta čekací rutina s časovačem a obřími long... mimochodem nevím jestli neni long 32bit.. já používám raděj definice uint32_t uint64_t..pak ti ty if() nikdy nebudou platit protože vždy přeteče wink

taktéž neznám definice pinů přes DDD5 DDB5 apod.. ale to bude asi fíčura tvejch knihoven..moje linuxácký to nevedou.. PD5 vs PB5 je klasika.. (jsou to jen makra za čísla 5 vs 5)

zkontroluj si MOSI - > DI  a MISO <- DO...

Web

(upravil Dohnalik 7. 5. 2012 16:03)

Re: Atmel AVR, SPI a C

OK, chtěl jsem zkontrolovat jen tu komunikaci přes SPI, jestli mám dobře to čtení zápis a práci s bity smile Tím ostatním jsem si jist, že to funguje. Když připojím napájení, tak se vše inicializuje a skočí to na konec kódu do else, které platí, když je to vyple (zapnuto = 0), tam se to snaží zapsat do CS8416 a už tam to zatuhne, takže bude chyba nejspíše HW. No zatím díky a já se s tím budu muset ještě poprat.
Jinak je to napsané prasácky, já vím, ale nenapadlo mě jak jinak to udělat, než s pomocí časovače, jelikož nepotřebuju, aby MCU stál, když nějaký vůl bude držet tlačítko smile

A ještě dotaz, proč mám na PB2 (SS pin) asi 1,2 V, když tam má být buď 0, nebo 5? V tom zatuhlém stavu.

Re: Atmel AVR, SPI a C

mohl sis nastavit větší děličku na časovač..počítat třeba po 0.1s .. v přerušení dekrementovat ty čekací promenné.. if(zpodezni) zpozdeni--.. v main vyhodnocovat stav zpozdeni a nastavovat je.. ale moznosti je hodne.. hlavne ze ti to nejak funguje

pokud je pin fakt vystupni, mužes mit ten pin usmaženej smile zkontroluj si jaky ma treba urovne kdyz k nemu zapojis 1k do zeme bez CS8416.. usmazeni vystupniho trandu se stava pri zkratu apod..

Web

(upravil Dohnalik 14. 5. 2012 14:59)

Re: Atmel AVR, SPI a C

OK, díky za pomoc, zítra si s tím pohraju smile
// funguje