Урок 48
Часть 1
USB DEVICE AUDIO
Предыдущий урок Программирование МК STM32 Следующая часть
Сегодня мы продолжим изучение нового интерфейса – шины I2S. И работать мы будем также, как и в прошлом уроке по I2S – с микросхемой CS43L22, установленной на плате STM32F4-DISCOVERY. Только в данном занятии мы попытаемся взять цифровой аудиопоток не из WAV-файла, а из ПК по шине USB, то есть мы попробуем из нашей платы создать звуковую карту. Звуковая карта получится, конечно, не полная, так как она будет работать только на воспроизведение (только в режиме ЦАП), но тем не менее, я думаю, работу с шиной I2S мы закрепим основательно, также коснёмся изучения другого класса USB – DEVICE Audio.
Свой проект мы создадим из старинного проекта, в котором не подключено ничего лишнего — TEST002, а назовём мы новый проект USB_DEVICE_AUDIO.
Откроем наш проект в Cube MX и произведём необходимые настройки.
Сначала выключим ненужные светодиоды, оставив только красный и зелёный.
Включим саму шину I2S
Ножки никакие не переопределяем. Оставим так как есть. Именно по этим ножкам и подключена микросхема Аудио ЦАП.
Отключим 6-й таймер
Включим USB_OTG_FS в режим Device_Only
В USB_DEVICE в разделе Class For FS IP выберем пункт Audio Device Class
Для работы лапки RESET микросхемы нам будет ещё необходимо включить на выход и настроить данную лапку порта (PD4)
В разделе «Clock Configuration» включим всё на максимум
Внесем также некоторые корректировки в настройки I2S
Также добавим и настроим DMA на шине I2S
В USB Device увеличим частоту дискретизации
Также желательно изменить дескриптор устройства, иначе если Вы уже использовали виртуальный порт, могут быть проблемы
А так как управление микросхемой происходит в отличии от основного аудио-потока уже по шине I2C, то необходимо включить ещё и эту шину. Включим шину I2C1
Лапку PB7 нужно будет переопределить на PB9. Я думаю, все уже умеют это делать. Сначала сбросим её, а затем переопределим
В Project -> Setting установим следующие настройки стека и кучи
Сгенерируем проект для среды Keil, настроим программатор на авторезет и скомпилируем проект.
Добавим в проект файлы, предназначенные для работы со звуком, audioplay.c и audioplay.h из проекта I2S_AUDIO.
Подключим файл audioplay.c в дереве Application/User
Также добавим подключение данной нашей библиотеки в главный модуль main.h
#include «stm32f4xx.h»
#include «audioplay.h»
Удалим здесь следующую строку:
uint8_t tim6_counter;
Уберём полностью весь код из бесконечного цикла
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_0)==GPIO_PIN_SET)
{
HAL_TIM_Base_Start(&htim6);
HAL_TIM_Base_Start_IT(&htim6);
}
else
{
tim6_counter=0;
HAL_TIM_Base_Stop(&htim6);
HAL_TIM_Base_Stop_IT(&htim6);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
}
В файле audioplay.c удалим подключение ненужных библиотек
#include «audioplay.h»
#include «fatfs.h»
#include «usb_host.h»
#include «lcd.h»
Также удалим ещё некоторые строки, связанные с использованием удалённых библиотек
static uint32_t WaveDataLength = 0;
—
extern FIL WavFile;
—
extern ApplicationTypeDef Appli_state;
char str2[20];
char str3[20];
—
UINT bytesread=0;
—
extern WAVE_FormatTypeDef *waveformat;
—
AudioTotalSize=waveformat->FileSize;
/*Get Data from USB Flash Disk*/
WaveDataLength=waveformat->FileSize;
—
LCD_SetPos(0,3);
LCD_String(str2);
LCD_String(str3);
Удалим ещё кое-какие ненужные объявления из файла audioplay.c
/* Position in the audio play buffer */
__IO BUFFER_StateTypeDef buffer_offset = BUFFER_OFFSET_NONE;
—
/* Defines for the Audio playing process */
#define PAUSE_STATUS ((uint32_t)0x00) /* Audio Player in Pause Status */
#define RESUME_STATUS ((uint32_t)0x01) /* Audio Player in Resume Status */
#define IDLE_STATUS ((uint32_t)0x02) /* Audio Player in Idle Status */
—
#define AUDIO_RESET_GPIO_CLK_ENABLE() __GPIOD_CLK_ENABLE()
—
/* Variables used in normal mode to manage audio file during DMA transfer */
uint32_t AudioTotalSize = 0xFFFF; /* This variable holds the total size of the audio file */
int32_t AudioRemSize = 0xFFFF; /* This variable holds the remaining data in audio file */
uint16_t *CurrentPos ; /* This variable holds the current position of audio pointer */
—
__IO uint32_t PauseResumeStatus = IDLE_STATUS;
—
static uint32_t WaveDataLength = 0;
—
#define AUDIO_BUFFER_SIZE 0X8000
—
uint8_t Audio_Buffer[AUDIO_BUFFER_SIZE];
AUDIO_StateMachine Audio;
uint32_t samplerate;
uint32_t offsetpos;
uint32_t cnt;
uint32_t dur; //переменная для оставшегося времени воспроизведения файла
Функции AudioPlay_Init и AudioPlay_Start удалим со все содержимым
void AudioPlay_Init(uint32_t AudioFreq)
{
samplerate = AudioFreq;
__IO uint8_t volume=70;
if(AudioOut_Init(OUTPUT_DEVICE_AUTO, volume, samplerate)!=0)
{
Error();
}
}
//——————————————————
void AudioPlay_Start(uint32_t AudioFreq)
{
—
}
Также удалим содержимое функций-обработчиков событий и слегка их переименуем
//——————————————————
void AudioPlay_HalfTransfer_CallBack(void)
{
}
//——————————————————
void AudioPlay_TransferComplete_CallBack(void)
{
}
Переименуем функцию также в файле audioplay.h в объявлении её прототипа
void AudioPlay_HalfTransfer_CallBack(void);
void AudioPlay_TransferComplete_CallBack(void);
Также подключим в этом файле файл usbd_audio_if.h
#include «stm32f4xx_hal.h»
#include «usbd_audio_if.h»
Удалим из этого файла объявление функции
void AudioPlay_Start(uint32_t AudioFreq);
А объявление функции AudioPlay_Init откорректируем в объявление другой функции
uint8_t AudioOut_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq);
Также удалим все объявления переменных и структур кроме SPI3, а вместо них добавим другие, взяв их из си-файла
#include «usbd_audio_if.h»
//————————————————
#define I2S3 SPI3
/* Codec output DEVICE */
#define OUTPUT_DEVICE_SPEAKER 1
#define OUTPUT_DEVICE_HEADPHONE 2
#define OUTPUT_DEVICE_BOTH 3
#define OUTPUT_DEVICE_AUTO 4
/* Audio status definition */
#define AUDIO_OK ((uint8_t)0)
#define AUDIO_ERROR ((uint8_t)1)
#define AUDIO_TIMEOUT ((uint8_t)2)
//————————————————
uint8_t AudioOut_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq);
Добавим ещё пару макросов
/* Codec POWER DOWN modes */
#define CODEC_PDWN_HW 1
#define CODEC_PDWN_SW 2
Вставим обработчики прерываний в main.c
/* USER CODE BEGIN 4 */
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s3)
{
if(hi2s3->Instance == I2S3)
{
AudioPlay_TransferComplete_CallBack();
}
}
//—————————————————————————
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
if(hi2s->Instance == I2S3)
{
AudioPlay_HalfTransfer_CallBack();
}
}
/* USER CODE END 4 */
Подключим нашу плату к ПК, и ST-Link, и USB OTG
Соберём проект, прошьём контроллер и убедимся, что драйвер нашей будущей звуковой карты у нас нормально установился
В файл usbd_audio_if.c подключим нашу библиотеку
/* USER CODE BEGIN INCLUDE */
#include «audioplay.h»
/* USER CODE END INCLUDE */
В этом же файле в функции AUDIO_Init_FS вызовем инициализацию микросхемы
static int8_t AUDIO_Init_FS(uint32_t AudioFreq, uint32_t Volume, uint32_t options)
{
/* USER CODE BEGIN 0 */
AudioOut_Init(OUTPUT_DEVICE_AUTO, Volume, AudioFreq);
return (USBD_OK);
/* USER CODE END 0 */
}
В следующей части занятия мы напишем ещё несколько функций и подключим их в обработчики команд драйвера звуковой карты.
Предыдущий урок Программирование МК STM32 Следующая часть
Техническая документация на Аудио ЦАП CS43L22
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добрый день, на сколько я понял если в кубе настроить i2s и сгенерить его в кейл то транспорт будет работать? Все настройки и изменения в маин касаются управления цап?