![]() |
|
Atmel AVR, SPI a C - Printable Version +- Audioweb.cz (https://www.audioweb.cz) +-- Forum: Ostatní (https://www.audioweb.cz/forumdisplay.php?fid=16) +--- Forum: Smetiště (https://www.audioweb.cz/forumdisplay.php?fid=21) +--- Thread: Atmel AVR, SPI a C (/showthread.php?tid=16062) Pages:
1
2
|
Atmel AVR, SPI a C - Dohnalik - 7. 5. 2012 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. Kód: /*
* 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
}
}
}Atmel AVR, SPI a C - luta - 7. 5. 2012 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 )..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 ![]() 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... Atmel AVR, SPI a C - Dohnalik - 7. 5. 2012 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 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 ![]() 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. Atmel AVR, SPI a C - luta - 7. 5. 2012 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 zkontroluj si jaky ma treba urovne kdyz k nemu zapojis 1k do zeme bez CS8416.. usmazeni vystupniho trandu se stava pri zkratu apod..
Atmel AVR, SPI a C - Dohnalik - 7. 5. 2012 OK, díky za pomoc, zítra si s tím pohraju ![]() // funguje |