Почему не работает моя связь по SPI? (Atmega644)

Я создаю драм-машину, и я сохранил образец файла заголовка со звуком бочки, который принимает значения от 0 до 170. Я хочу отправить его через SPI на 10-битный ЦАП MCP4811, который затем выводит его на 3,5 мм аудиоразъем.

Мои контакты MISO, MOSI, SCK и RESET подключены к моему USB-программатору, а также к ЦАП.

Вот фрагмент аудиофайла, хранящегося в «samples.h»

unsigned const char sample_1[2221] PROGMEM = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, ...}
unsigned int sample_len[1] = {2221}

Итак, это образец из 2221 бит. Это я хочу отправить на ЦАП, используя SPI с частотой = 22 кГц.

Я использую кристалл с частотой 16 МГц, поэтому я установил предохранители, чтобы использовать его.

Я использую таймер, который выходит за пределы 22 кГц.

volatile unsigned int sample_count[1] = {0};
volatile unsigned int audio_out = 0;
volatile unsigned char spi_junk;

int main (void)
sei();
DDRB = 0b10110000; //Set MOSI, SCK and SS as output.
PORTB = (1 << PINB4) //active low on SS.

TIMSK1 = (1<<OCIE1A); //Enable interrupt
TCCR1B = (1<<WGM12) | (1<<CS11); // set CTC mode and divide clk by 8 
OCR1A = 91; //16 MHz/(8*91) ~ 22068 Hz

//SPI Init
SPCR = (1<<SPE) | (1<<MSTR);  //master, 8 MHz
SPSR = (1<<SPI2X);

ISR (TIMER1_COMPA_vect) {
    audio_out = 0;

//If play_track == 1, then the sound should be played back.
if (play_track && sample_count[0] < sample_len[0]){
   audio_out += (pgm_read_byte(&(sample_1[sample_count[0]++)));

// send audio_out to 10-bit DAC on SPI
PORTB &= ~(1<<PINB4); // B.4 (DAC /CS)
SPDR = (char) ((audio_out >> 6) & 0x000f); //byte 1 0 0 0 0 b9 b8 b7 b6
while (!(SPSR & (1<<SPIF)));
spi_junk = SPDR;

SPDR = (char) ((audio_out & 0x003f) << 2); //byte 2 b5 b4 b3 b2 b1 b0 0 0
while (!(SPSR & (1<<SPIF)));
spi_junk = SPDR;
PORTB |= (1<<PINB4);
}

Мой PIN-код установлен.

Atmega644 -> ЦАП

MOSI -> SDI

SCK -> SCK

SS -> /CS

На MCP4811

Vdd -> 5V

Vss -> GND

V_out -> Audio jack.

Остальные пины на MCP4811 ни к чему не подключены.

Я видел, что audio_out работает должным образом, отображая значение audio_out на ЖК-экране. Но на ЦАП ничего не выводится. Кто-нибудь видит, что может быть не так?

РЕДАКТИРОВАТЬ: добавлен SPI init, который я пропустил.


person sss    schedule 24.04.2019    source источник


Ответы (2)


Ваша линия здесь

SPDR = (char) ((audio_out >> 6) & 0x000f); //byte 1 0 0 0 0 b9 b8 b7 b6

Установит ¬SHDN в 0, что отключит ЦАП.

0 = Shutdown the device. Analog output is not available. VOUT pin is connected to 500 kohm typical)

Вместо этого установите бит 12 в 1

SPDR = (char) ((audio_out >> 6) & 0x0f)|0x10; //byte 1 0 0 0 1 b9 b8 b7 b6

из таблицы

1 = Active mode operation. VOUT is available.

person pm101    schedule 25.04.2019
comment
Почему SPDR установил это? Разве я не могу вместо этого просто подключить SHDN к шине 5V? - person sss; 25.04.2019
comment
В таблице указано The user can shut down the device using a software command (<SHDN> = 0) or SHDN pin. During shutdown mode, most of the internal circuits, including the output amplifier, are turned off for power savings - person pm101; 25.04.2019
comment
Но это ведь не через SPDR? То есть, если бы я назначил контакту SHDN на MCP4811 назначенный контакт на моем MCU и установил его на низкий уровень? - person sss; 25.04.2019
comment
См. Таблицу данных MCP4801 / 4811/4821 (DS22244B), стр. 22. "WRITE COMMAND REGISTER FOR MCP4811 (10-BIT DAC)" Бит ¬SHDN отправляется как часть команды WRITE REGISTER. Вывод¬SHDN должен иметь высокий уровень, а бит ¬SHDN в регистре ЦАП также должен иметь значение 1, иначе аналогового сигнала не будет. вывод на вывод Vout. The device will remain in Shutdown mode until the <SHDN> bit = 1 is latched into the device or SHDN pin is changed to logic high. Пожалуйста, попробуйте сначала, если это проблема, а может и нет (изменить один бит несложно) - person pm101; 25.04.2019
comment
Это был ответ в сочетании с настройкой SHDN на шину 5V. Спасибо! - person sss; 25.04.2019

В вашем коде нет инициализации SPI.

добавить в main()

SPSR = (1 << SPI2X);  // double speed (to get maximum of 8MHz output)
SPCR = (1 << SPE)  | (1 << MSTR); // 1:1 prescaler, master mode, SPI mode 0, SPI enable

Также несколько замечаний к вашему коду:

используйте sei() только после завершения всех инициализаций, чтобы избежать прерывания неинициализированного периферийного устройства.

Лучше сначала установить высокий уровень PB4, а затем настроить его как выход, чтобы избежать низкого уровня выходного сигнала PB между двумя командами:

PORTB = (1 << PINB4) //active low on SS.
DDRB = 0b10110000; //Set MOSI, SCK and SS as output.
person AterLux    schedule 25.04.2019
comment
Спасибо, что обратили внимание на то, что, к сожалению, это я плохо справился с заданием вопроса. Эти строки у меня уже были. Еще у меня SPCR = (1 ‹★ SPE) | (1 ‹---------------- MSTR) | (1 ‹---------------- CPOL); - person sss; 25.04.2019