Теперь вот соединяю вместе и есть проблема. Надранные функции уже принимают аргумент (в моем случае - адрес блока в байтовой адресации) комманды в виде 32 битного числа, деленного на четыре части (char по 8 бит), которые потом по байту передаются через SPI карте. В своем цикле считывания использую 32 битное число и с помощью масок и сдвига делю его (с самостоятельной реализацией были косяки, компилятор ругался на выхождении из границ. решил глянуть еще либы, как там сделано деление (она принимала уже 32 битное число на входе), там точно так же. взял ее реализацию).
Ну и логика такова: настраиваем ШИМ, таймер. Потом считываем блок с карты, сбрасываем номер текущего семпла, разрешаем прерывания и звук должен играться. Прерывание проверяет оставшееся количество семплов и, если оно кончилось, то запрещает прерывания (чтобы они не мешали процессу считывания с карты нового блока). Цикл считывания тоже следит за семплами. Если они кончились - начинается новая итерация цикла, он считывает данные, сбрасывает текущий проигрываемый семпл в ноль, разрешает прерывания и снова ждет.
Но что-то в коде не так и на выходе имею циклический шум. Похоже на то, что считанный блок данных закольцован (что-то не так со считыванием). В коде до этого так же находил ляпы, но вроде уже все, что нашел вчера, прилизал. Попробую проверить отдельно цикл считывания без прерываний, шима, таймеров, и, соответственно, вывода звука. Да, знаю, что мое включение-выключение прерываний глупо, но пока другого способа не придумал. Потом еще способ "сначала прочитаем, а после проиграем" будет давать переодические щелчки (задержки) звука. Но это потом я как-то закольцую или сделаю два буффера. Просто более сложную схему более сложно отлаживать, а тут и простая не пашет.
Код проекта прилагаю, МК AtMega8a, тактирование 8 мгц внутренней цепочкой. Возможно, своими наметанными глазами найдете ошибки, которые я не замечаю сейчас
Спойлер
Код: Выделить всё
#include <avr/io.h>
#include <string.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define SAMPLE_RATE 8000;
uint16_t sample;
int sample_count;
#define DI 3
#define DO 4
#define CLK 5
#define CS 0
#define LED 6
#define pcm_length 512
#define LED_ON PORTB |= _BV(LED)
#define LED_OFF PORTB &= ~_BV(LED)
char buffer [512]={}; //Buffer
void spi_transmit (unsigned char data) { //transmit byte to SD|MMC card
unsigned char i;
for (i=0;i<8;i++)
{
if ((data&0x80)==0x00) PORTB&=~_BV(DI); //Set data bit
else PORTB|=_BV(DI);
data=data<<1;
PORTB|=_BV(CLK); //Strobe
asm("nop");
PORTB&=~_BV(CLK);
}
}
unsigned char spi_receive (void) { //receive byte from SD|MMC card
unsigned char i, res=0;
for (i=0;i<8;i++)
{
PORTB|=_BV(CLK); //Start strobe
res=res<<1;
if ((PINB&_BV(DO))!=0x00) res=res|0x01; //Get data bit
PORTB&=~_BV(CLK); //End strobe
asm("nop");
}
return res;
}
unsigned char sd_cmd(char b0, char b1, char b2, char b3, char b4, char b5) {
unsigned char res;
long int count;
spi_transmit (b0); //transmit index
spi_transmit (b1); //transmit argument
spi_transmit (b2);
spi_transmit (b3);
spi_transmit (b4);
spi_transmit (b5); //transmit CRC
count=0;
do { //wait to R1 responce
res=spi_receive();
count=count+1;
} while ( ((res&0x80)!=0x00)&&(count<0xffff) );
return res;
}
unsigned char sd_card_init(void) { // Отправка комманды на карту
unsigned char i,temp;
long int count;
for (i=0;i<10;i++) //80 strobes
spi_transmit (0xff);
PORTB&=~_BV(CS); //CS enable
temp=sd_cmd (0x40,0x00,0x00,0x00,0x00,0x95); //CMD0
if (temp!=0x01) return 3; //Exit, if bad responce
spi_transmit (0xff);
count=0;
do{
temp=sd_cmd (0x41,0x00,0x00,0x00,0x00,0x95); //CMD1
spi_transmit (0xff);
count=count+1;
} while ( (temp!=0x00)&&(count<0xffff) ); //Wait 0x01 responce
if (count>=0xffff) return 4;
return 0;
}
unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) {
unsigned char temp;
long int count;
temp=sd_cmd (0x51,a1,a2,a3,a4,0x95); //Send CMD17
if (temp!=0x00) return 5; //Exit, if responce not 0x00
spi_transmit (0xff);
count=0;
do{ //Wait to data block starts
temp=spi_receive();
count=count+1;
} while ( (temp!=0xfe)&&(count<0xffff) );
if (count>=0xffff) return 5;
for (count=0;count<512;count=count+1) //receive data block
buff[count]=spi_receive();
spi_receive(); //receive CRC
spi_receive();
return 0;
}
// a* - разбитый аргумент комманды CMD17, который полностью является адресом блока (адресация побайтная???)
unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) {
unsigned char temp;
long int count;
temp=sd_cmd(0x58,a1,a2,a3,a4,0x95); //Send CMD24
if (temp!=0x00) return 6; //Exit, if responce non 0x00
spi_transmit (0xff);
spi_transmit (0xfe); //Start data block
for (count=0;count<512;count=count+1) //Send data block
spi_transmit(buff[count]);
spi_transmit (0xff); //Send CRC
spi_transmit (0xff);
temp=spi_receive();
if ((temp&0x05)!=0x05) return 6; //Exit, if data responce non 0x05
count=0;
do { //Wait end of busy state responce
temp=spi_receive();
count=count+1;
}while ( (temp!=0xff)&&(count<0xffff) );
if (count>=0xffff) return 6;
return 0;
}
ISR(TIMER0_OVF_vect)
{
sample_count--;
if (sample_count == 0)
{
sample_count = 4;
OCR1A = buffer[sample++];
if(sample == pcm_length) cli();
}
}
/* initialise the PWM */
void pwm_init(void)
{
/* use OC1A pin as output */
//DDRB = 0xFF;
/*
* clear OC1A on compare match
* set OC1A at BOTTOM, non-inverting mode
* Fast PWM, 8bit
*/
TCCR1A = _BV(COM1A1) | _BV(WGM10);
/*
* Fast PWM, 8bit
* Prescaler: clk/1 = 8MHz
* PWM frequency = 8MHz / (255 + 1) = 31.25kHz
*/
TCCR1B = _BV(WGM12) | _BV(CS10);
/* set initial duty cycle to zero */
OCR1A = 0;
/* Setup Timer0 */
TCCR0|=(1<<CS00);
TCNT0=0;
TIMSK|=(1<<TOIE0);
sample_count = 4;
}
int main(void) {
unsigned char temp;
uint32_t i;
PORTB=_BV(CS)|_BV(DO)|_BV(DI); //Init ports
DDRB=_BV(CS)|_BV(DI)|_BV(CLK)|_BV(1);
temp=sd_card_init(); //Init card
if (temp==0x00) {
pwm_init();
if(temp==0x00) {
for(i = 0x0; i <= 0x41200; i += 0x200) {
/*
0b00000000 00000000 00000000 00000000
*/
LED_ON;
sample = 0;
temp=read_block(
buffer,
(i & 0xFF000000UL) >> 24,
(i & 0x00FF0000UL) >> 16,
(i & 0x0000FF00UL) >> 8,
(i & 0x000000FFUL) >> 0
);
sei();
while(sample!=pcm_length) {
asm("nop");
}
LED_OFF;
}
}
}
while (1)
LED_OFF
;
return 1;
}


