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
}
}
}