Проблема с проигрыванием звука с карты

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Сообщения: 36
Зарегистрирован: Пт авг 27, 2010 09:56:25

Сообщение Ticksy »

Изучаю AVR мк, есть парочку проектов с общей базой (часы-будильник и таймер-часы-будильник-управлялся_кондеем, отличия по сути в индикаторах и в возможном отсутствии внешней памяти у второго проекта). Разбираюсь сейчас с работой картой памяти и с выводом звука через ШИМ (R-2R ЦАП жрет выводы, а разброс резюков сильно сказывается на качестве). Стараюсь делать все проще, да и по возможности делать самому, ибо цель еще - прокачка навыков. Файловую систему на карте не брал, ибо для атмеги8, которая используется в проекте, тяжеловато (пол оперативки и пол флеша точно надо отдать. проще накалякать свою простенькую, чтобы не тратить ресурсы. да и не нужна мне полноценная). Читаю напрямую блоками софтово. С ШИМ разобрался, из встроенного флеша играет ~7.5к семплов нормально.

Теперь вот соединяю вместе и есть проблема. Надранные функции уже принимают аргумент (в моем случае - адрес блока в байтовой адресации) комманды в виде 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;
}
Ковырянием выяснил, что цикл вычисляет адресацию правильно. Заполняет (записывает) область верно. Вставлял проверку на ошибку чтения - на ней валится. Но непонятно почему... выведу еще с платы UART, ибо со светодиодом много данных не передашь.
Реклама
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Пт сен 21, 2007 17:53:23
Откуда: Зарайск

Сообщение mrFox »

1) int sample_count; - надо сделать volatile, иначе цикл в main не увидит изменения в прерывании
2) CS нужно опускать перед чтением/записью и поднимать по окончанию чтения/записи
3) код инициализации подходит под MMC, SDC v1.x; v2 и HC в пролете
Реклама
Первый раз сказал Мяу!
Сообщения: 36
Зарегистрирован: Пт авг 27, 2010 09:56:25

Сообщение Ticksy »

Спасибо. Пункты 1 и 2 исправил наскоро (дабы проверить будет ли толк), но пока не видно. По идее CS должен быть лишь вреден тем, что карта ожидает обращения и может что-то гипотетически навестись. Я согласен, что это не совсем правильно, но нужно еще постараться и тактировать процесс обмена наводками. Дело походу в другом... Ну а инициализация карты вполне может быть не универсальна, я потом для больших карт памяти буду допиливать (если конечно буду их использовать. текущая карта на 512 мб вполне работает и ее более чем хватает).

Текущий вариант кода:
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <string.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
//#include <avr/delay.h>
#define SAMPLE_RATE 8000;

uint16_t sample;
volatile 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)

#define SD_DOWN PORTB&=~_BV(CS)
#define SD_UP PORTB |= _BV(CS)

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);
	
	SD_DOWN;							//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
	
	SD_UP;

	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)
{
	cli();
	sample_count--;
	if (sample_count == 0)
	{
		sample_count = 4;
		OCR1A = buffer[sample++];
	}
	if(sample != pcm_length) {
		sei();
	}
}

/* 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;
}

/*void beep(char count) {
	char i,j;
	for(i = 0; i < count; i++) {
		for(j = 0; j < 255; j++) {
			PORTB |= _BV(1);
			_delay_ms(50);
			PORTB &= ~_BV(1);
			_delay_ms(50);
		}
		_delay_ms(500);
	}
}*/

int main(void) {
	unsigned char temp;
	uint32_t i;
	LED_OFF;
	cli();
	temp=sd_card_init();   //Init card
	PORTB=_BV(CS)|_BV(DO)|_BV(DI); 	//Init ports
	DDRB=_BV(CS)|_BV(DI)|_BV(CLK)|_BV(1);
	//pwm_init();
	if(temp==0x00) {
		for(i = 0x0; i <= 0x41200; i += 0x200) {
			/*
			0b00000000 00000000 00000000 00000000
			*/
			//LED_ON;
			sample = 0;
			sample_count = 4;
			SD_DOWN;
			temp=read_block(
				buffer,
				(i & 0xFF000000UL) >> 24,
				(i & 0x00FF0000UL) >> 16,
				(i & 0x0000FF00UL) >> 8,
				(i & 0x000000FFUL) >> 0
			);
			SD_UP;
			if(temp!=0x00) {
				//beep(2);
				//break;
			}

			sei();

			while(sample!=pcm_length) {
				asm("nop");
			}
			//LED_OFF;
		}
	} else {
		//beep(1);
	}

	while(1);
	
	return 0;
}
Походу еще регресс пошел, ибо звука вовсе не выводит (тот вариант, что выложен, как я помню, выводил зацикленный блок).
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Пт сен 21, 2007 17:53:23
Откуда: Зарайск

Сообщение mrFox »

pwm_init(); закоментарен поэтому звука и нет
извиняюсь что ввел в заблуждение volatile должен быть sample; - volatile uint16_t sample;
в общем volatile должны быть переменные используемые одновременно и в прерывании и в основной программе

посмотрите здесь
http://radiokot.ru/forum/viewtopic.php? ... 4&start=40
там osievskiy выкладывал исходник для SD - рабочий, у меня завелся и на stm32 и на xmega только функции инициализации и обмена переписать
и лучше использовать железный SPI
да при инициализации нужно установить частоту SPI меньше 400кГц (вроде нужно только для 80 стробов, но я всю инициализацию делаю на частоте 350кГц, потом повышаю)
Реклама
Эиком - электронные компоненты и радиодетали
Первый раз сказал Мяу!
Сообщения: 36
Зарегистрирован: Пт авг 27, 2010 09:56:25

Сообщение Ticksy »

В итоге взял первую версию из поста (ибо все же регресс пошел), поставил volatile и МК стал проигрывать звук :)). Естессно в звук прерывался на время чтения нового куска данных, так что закольцевал буфер. Стало играть нормально. На выход повесил электролит на 1 мкФ (чисто экспериментально, надо глянуть вообще расчет интегрирующей RC цепочки), пока без резюка (порт так можно попалить, если подключить слишком низкоомную нагрузку, да?). Частоту переделал под 31.25 кГц, больше на встроенном тактировании не выжать (оно еще и плавает: при 5 вольт играет по скорости нормально, при питании от лития - медленнее. но я живодер, питаю мк и карту от 5 вольт). Да и смысла нет особого до 44 кГц доводить.

SPI потом буду на аппаратный переделывать, ибо нечего ему простаивать. Да и экономней будет в плане тактов. Не понимаю зачем извращаются так при наличии свободного аппаратного (код был дернут с инета. для начала он хорош тем, что понятный). По качеству ничего, но фильтр на выходе надо доделывать. Оно конечно и так для будильника часов сойдет и неплохо бассит, но думаю, что можно чуть лучше еще получить звук.

Итоговый год выкладываю, вдруг кому пригодится или кто-то захочет покритиковать :).
Спойлер

Код: Выделить всё

#include <avr/io.h>
#include <string.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define SAMPLE_RATE 8000;

volatile uint16_t sample;
volatile 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)

volatile 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 (volatile 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 (volatile 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;
}

unsigned char start_read_block (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;

	return 0;
}

ISR(TIMER0_OVF_vect)
{
   
   //sample_count--;
   //if (1)//sample_count == 0)
   //{
      //sample_count = 4;
      OCR1A = buffer[sample++];
      if(sample == pcm_length) sample = 0;
   //}
}

/* 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;
	sample = 0;
}

int main(void) {
   unsigned char temp;
   uint32_t i;
   int j;

   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) {
		 temp=read_block(buffer, 0, 0, 0, 0);
		 sei();
         while (1) for(i = 0x0; i <= 0x1312d00; i += 0x200) {
            start_read_block(
			    (i & 0xFF000000UL) >> 24,
			    (i & 0x00FF0000UL) >> 16,
			    (i & 0x0000FF00UL) >> 8,
			    (i & 0x000000FFUL) >> 0
			);
			
            while(sample < 256) {
               asm("nop");
            }
			
			for(j = 0; j < 255; j++) buffer[j] = spi_receive();
			
			while(sample > 255) {
				asm("nop");
			}
			
			for(j = 255; j < 512; j++) buffer[j] = spi_receive();
			spi_receive();
			spi_receive();
         }
      }
   }

   while (1)
   LED_OFF
   ;

   return 1;
}
Еще раз спасибо :)).
Реклама
Нашел транзистор. Понюхал.
Сообщения: 190
Зарегистрирован: Пт сен 21, 2007 17:53:23
Откуда: Зарайск

Сообщение mrFox »

ну и хорошо :music:
надо только не забыть про 400кГц при инициализации
а то аппартный SPI быстрее и я с этим неделю ковырялся, пока завел
Реклама
Ответить

Вернуться в «AVR»