Atmega8+Microsd

27-08-2013, 19:01 От: admin Посмотрели: 1342
Добрый день форумчане) Решил сделать стерео wav плеер на Atmega8. Перечитал кучу статей про работу MicroSD, вроде как разобрался, спаял схему, написал код. На флешке (transcend 2gb) файловой системы нет, песня записана с 0-ого адреса первый сектор и т. д. SPI - сделал програмно. С апаратным у меня вобще не работало не чего)

Все отлично работает если командой CMD18 начинать чтение с 0 адреса. А если чтение начать с второй песни, адрес например 42831*200h. не работает писки какието в динамике. Может кто работал с флешками, может какието нюансы есть перед тем как адресовать? Интерестно если адрес поставить 100*200h то работает, первая песня начинаеться не с начала и если дальше повышать адрес перестает работать не понимаю как так получаеться.


#include <mega8.h> // ATmega 8 юзаем.
#include <delay.h> // Модуль задержек.
// Назначение вх-вых МК(порт D) - карта памяти (програмный spi).
#define DI 0 // Порт D пин 0 это выход из МК и вход в карту памяти (данные из МК)
#define DO 3 // Порт D пин 3 это вход в МК и выход из карты памяти (данные из карты памяти)
#define CLK 2 // Порт D пин 2 это выход из МК и вход в карту памяти (тактовый сигнал)
#define CS 1 // Порт D пин 1 это выход из МК и вход в карту памяти (выбор карты памяти: "0" - выбрана, "1" - не выбрана)
// Упрощение процедур записи/чтения битов и тактированния програмного spi
#define Init_SPI DDRD |= (1 << CS)|(1 << CLK)|(1 << DI); PORTD |= (1 << CS)|(1 << CLK)|(1 << DO)|(1 << DI); // Настроойка порта.
#define Set_0_DI PORTD &= ~(1 << DI) // Set_0_DI устанавливает "0" на DI порта D.
#define Set_1_DI PORTD |= (1 << DI) // Set_1_DI устанавливает "1" на DI порта D.
#define Get_X_DO PIND & (1 << DO) // Get_X_DO считать бит с линии DO порта D.
#define BeginTakt PORTD |= (1 << CLK) // BeginTakt устанавливает "1" на CLK порта D.
#define EndTakt PORTD &= ~(1 << CLK) // EndTakt устанавливает "0" на CLK порта D.
#define SelectCard PORTD &= ~(1 << CS) // SelectCard устанавливает "0" на CS порта D.
#define DeSelectCard PORTD |= (1 << CS) // DeSelectCard устанавливает "1" на CS порта D.
// Команды для карт памяти.
#define CMD0 (0x40+0) // Программный сброс карты памяти (любой).
#define ACMD41 (0xC0+41) // Запуск процесса инициализации карты типа SDC (microsd).
#define CMD12 (0x40+12) // Прекратить чтение данных.
#define CMD18 (0x40+18) // Чтение множества блоков (секторов).
#define CMD55 (0x40+55) // Команда должна посыллаться перед ACMD командами.
// Процедура передачи байта карте по SPI.
void SPI_Write (unsigned char Data)
{
unsigned char i; // Cчетчик битов 0..7.
for (i = 0; i < 8; i++) // Цикл перебора битов отправляемого байта.
{ // Передача начинается из старшего бита: 2в7, 2в6 ... 2в0.
if ((Data & 0x80) == 0x00) // Если i-ый бит = 0 то.
Set_0_DI; // Установить бит данных "0".
else // Иначе.
Set_1_DI; // Установить бит данных "1".
Data = Data << 1; // Переход (сдвиг) к следующему биту данных.
BeginTakt; // Импульс такта начали (0->1).
#asm("nop"); // Пауза в 1 такт CPU.
EndTakt; // Импульс такта закончили (1->0).
}
}
// Процедура приема байта от карты по SPI.
unsigned char SPI_Read (void)
{
unsigned char i, Data = 0x00; // Cчетчик битов 0..7 и пустой байт.
for(i = 0; i < 8; i++) // Цикл перебора битов принемаемого байта.
{ // Прием начинается из старшего бита: 2в7, 2в6 ... 2в0.
BeginTakt; // Импульс такта начали (0->1).
Data = Data << 1; // Переход (сдвиг) к следующему биту данных.
if (Get_X_DO) // Если на входе DO "1" то.
Data = Data | 0x01; // Установить i-ый бит в принемаемом байте "1" иначе не делать ничего (оставить "0").
EndTakt; // Импульс такта закончили (1->0).
#asm("nop"); // Пауза в 1 такт CPU.
}
return Data; // Возвращаем байт.
}
// Процедура передачи команд карте памяти (cmd - команда, arg - аргумент команды).
unsigned char Send_CMD (unsigned char cmd, long int arg)
{
unsigned char crc, res; // Контрольная самма, счетчик и результат процедуры.
if (cmd & 0x80) // Если команда формата ACMD самый старший бит = "1" то.
{
cmd &= 0x7F; // Востановим комамнду (уберем самый старший бит = "0")
res = Send_CMD(CMD55, 0); // Перед ACMD командами нужно посылать CMD55 по даташиту.
if (res > 1) return res; // Если ответ команды больше еденицы, возвращаем код ошибки.
}
DeSelectCard; // Откл. карту.
SPI_Write (0xff); // Байт ждем.
SelectCard; // Выберем карту.
SPI_Write (0xff); // Байт ждем.
SPI_Write (cmd); // Посылаем команду карте.
SPI_Write (arg >> 24); // Посылаем аргумент карте биты [31..24].
SPI_Write (arg >> 16); // Посылаем аргумент карте биты [23..16].
SPI_Write (arg >> 8); // Посылаем аргумент карте биты [15..8].
SPI_Write (arg); // Посылаем аргумент карте биты [7..0].
crc = 0x01; // Контрольная сумма = 1.
if (cmd == CMD0) crc = 0x95; // Для команды CMD0 контрольная сумма = 0x95;
SPI_Write (crc); // Записываем контрольную сумму.
crc = 16; // Счетчик = 16.
do // 10 раз пытаемся получить ответ на команду.
{
SPI_Write (0xff); // Запишим байт ff.
res = SPI_Read(); // Прочитаем байт.
}
while ((res & 0x80) && --crc);// Если самый старший бит ответа = "1" и счетсик попыток меньше 16 то ответ получен.
return res; // Возвращаем ответ на команду ("0" - выполнено, "1" - выполняется, больше "1" коды ошибок).
}
// Процедура инициализации карты памяти.
unsigned char Card_Initialize (void)
{
unsigned int i; // Счетчик.
unsigned char res; // Результат.
Init_SPI; // Настройка выводов порта.
for (i = 0; i < 16; i++) SPI_Write (0xff); // Отправляем 16 байт 0xff в не выбранную карту памяти.
SelectCard; // Выбираем карту памяти.
if (Send_CMD(CMD0, 0) == 1) // Если команда на сброс принята то.
{
res = Send_CMD(ACMD41, 0); // Команда начать инициализацию карты памяти типа microsd.
if (res == 0x01) // Если инициализация выполняется.
{ // Посылаем команду инициализации и проверяем ответ = "0" (выполнено).
i = 0xffff; // Счетчик на максимум.
do
{
res = Send_CMD(ACMD41, 0); // Посылаем команду инициализации
}
while ((res != 0) && --i); // Проверяем ответ = "0" и счетчик дошел до нуля или нет.
}
else return 1; // Инициализация не выполнилась.
if (i == 0) return 1; // Инициализация не выполнилась.
}
else return 1; // Инициализация не выполнилась.
SPI_Write (0xff); // Завершение байтом 0xff.
return 0; // Карта инициализирована.
}
// Процедура прерывания чтения с карты.
void Stop_Read(void)
{
unsigned int i; // Счетчик.
unsigned char res; // Результат.
Send_CMD(CMD12, 0); // Прекратить чтение данных.
SPI_Write (0xff); // 8 байт макс. задержка ответа на команду
SPI_Write (0xff); // ждем посылая)
SPI_Write (0xff);
SPI_Write (0xff);
SPI_Write (0xff);
SPI_Write (0xff);
SPI_Write (0xff);
SPI_Write (0xff);
i = 0xffff; // Счетчик на максимум.
do
{
SPI_Write (0xff); // Запишим байт ff.
res = SPI_Read(); // Прочитаем байт.
delay_us(100);
}
while ((res!= 0xff) && --i); // Если сигнатура данных принята то.
SPI_Write (0xff);
PORTB.4 = 0;
TIMSK=0x00;
}
// Процедура проигрывания аудиоданных из карты памяти.
unsigned char Play_Myzon (void)
{
unsigned int i; // Счетчик.
unsigned char res; // Результат.
res = Send_CMD(CMD18, 0); // Чтение множества блоков (секторов).
if (res != 0x00) return 0; // Если ошибка то выход.
do
{
i = 0xffff; // Счетчик на максимум.
do
{
SPI_Write (0xff); // Запишим байт ff.
res = SPI_Read(); // Прочитаем байт.
}
while ((res!= 0xfe) && --i); // Если сигнатура данных принята то.
for (i = 0; i < 256; i++) // Читаем данные посекторно.
{
OCR1A = SPI_Read(); // И на прямую подаем их
OCR1B = SPI_Read(); // на апаратный ШИМ 8 бит, 57,602 кГц.
delay_us(50); // Задержкой управляем скоростью воспроизведения ~ 48,000 кГц
}
SPI_Read(); // CRC
SPI_Read(); // CRC
if (PINC.0 == 0) {Stop_Read(); return 0;} // стоп.
}
while (1); // Бесконечный цикл воспроизведения.
}
interrupt[TIM0_OVF] void Timer8bit (void) // Для нормального воспроизведения 44100 с буфером.
{
TCNT0=0xd6;
}
void main(void)
{
DDRB = 0xff; // Насторйка портов.
PORTB = 0b00000110;
DDRC = 0x00;
PORTC = 0xff;
OCR1A = 0x00; // Настройка тайммера 1 на FastPWM - 2 канала.
OCR1B = 0x00;
TCCR1A = (1<<7)|(1<<5)|(1<<0);
TCCR1B = (1<<0)|(1<<3);

TCNT0=0xd6; // Настройка таймера 0 на 44100 или 48000гц.
TCCR0=0x02;
TIMSK=0x00;
SREG = 1<<7;

delay_ms(1000);
Card_Initialize(); // Инициализация карты памяти.
while(1)
{
if (PINC.1 == 0) {PORTB.4 = 1; TIMSK=0x01; Play_Myzon();} // Воспроизведение.
}
}

Раздел: МК для начинающих

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться, либо войти на сайт под своим именем.

Обсудить на форуме


На момент добавления Atmega8+Microsd все ссылки были рабочие.
Все публикации статей, книг и журналов, представлены на этом сайте, исключительно для ознакомления,
авторские права на эти публикации принадлежат авторам статей, книг и издательствам журналов!
Подробно тут | Жалоба
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.


Опрос

Ваши предпочтения в TRX


Одинарное преобразование
Двойное преобразование
Прямое преобразование
SDR
Другое
Мне всё равно

Популярные новости
Календарь новостей
«    Май 2024    »
ПнВтСрЧтПтСбВс
 12345
6789101112
13141516171819
20212223242526
2728293031