STM32 I2S.

STM32 I2S.

Протокол I2S, не путать с I2C, предназначен для передачи аудио потока. В моем устройстве этот протокол используется для передачи аудио потока между кодеком и МК.
Сразу хотелось бы отметить, что как такового отдельного модуля I2S у STM32 нет, а тот что есть реализуется на основе модуля SPI и тот же регистр DR[0:15] у них общий.

I2S у STM32 обладает следующими особенностями:
  • дуплексная передача
  • полудуплексная передача(только приемник или передатчик)
  • может работать как в режиме master так и в режиме slave
  • восьми битный программируемый делитель позволяет с высокой точностью задавать аудио частоту от 8KHz до 192KHz
  • передача данных в 16, 24. 32 битном формате
  • размер пакета зависит от размера данных, 16 бит для 16 битных данных и 32 бита для для 16, 24, 32 битных данных на один аудио канал
  • программируемая полярность тактового сигнала
  • флаг опуcтошения в режиме slave при передаче, флаг ошибки пакета при приеме и передаче в режиме slave, флаг переполнения при приеме в обоих режимах
  • один шестнадцати битный регистр для приема и передачи данных для обоих каналов

  • поддерживает протоколы:
    – I2S Phillps standard
    – MSB-justified standard (left-justified)
    – LSB-justified standard (right-justified)
    – PCM standard (with short and long frame synchronization on 16-bit channel frame
    or 16-bit data frame extended to 32-bit channel frame)

  • данные всегда передаются старшим битом вперед
  • можно использовать DMA с шириной шины 16 бит для приема и передачи
  • master clock можно вывести наружу, для тактирования внешних аудио компонентов с фиксированной частотой 256*Fs
  • для достижения высокой точности тактирования используется отдельный PLL
  • может тактироваться от внешнего источника через вывод I2S_CKIN


Структуру модуля, можно посмотреть на картинке ниже, кликнув по ней.
STM32 I2S.

Так же хотелось бы обратить внимание на отдельный PLL, с помощью которого достигается необходимая частота тактирования.
STM32 I2S.


Еще один интересный момент на которое хотелось бы обратить внимание, что МК может работать в как в режиме Master, так и в режиме Slave. Отличаются они тем, что Master выдает тактирующий сигнал, Slave же просто его принимает.

Регистр конфигурации SPI_I2SCFGR:

I2SMOD(I2S mode selection) — единица в этом бите переводит модуль в режим I2S, иначе модуль работает в режиме SPI.

I2SE(I2S Enable) — единица в этом бите включает модуль I2S.

I2SCFG(I2S configuration mode) — битовое поле предназначено для конфигурации в режиме I2S.
00: Slave - transmit
01: Slave - receive
10: Master - transmit
11: Master - receive

PCMSYNC(PCM frame synchronization) — единица в этом бите включает длительную синхронизацию кадра.

I2SSTD(I2S standard selection) — битовое поле позволяет выбрать один из проколов.
00: I2S Philips standard.
01: MSB justified standard (left justified)
10: LSB justified standard (right justified)
11: PCM standard

CKPOL(Steady state clock polarity) — бит позволяет задать полярность сигнала в режиме ожидания. 0 — низкий уровень в режиме ожидания, 1 — высокий уровень в режиме ожидания.

DATLEN(Data length to be transferred) — битовое поле позволяет задать формат передачи данных.
00: 16-bit data length
01: 24-bit data length
10: 32-bit data length
11: Not allowed

CHLEN(Channel length (number of bits per audio channel)) — бит позволяет задать длину пакета для одного канала.


Регистр предделителя SPI_I2SPR

MCKOE(Master clock output enable) — единица в этом бите позволяет вывести наружу master clock.

ODD(Odd factor for the prescaler) — бит позволяет влиять на делитель. В случае если установлен ноль делитель вычисляется по формуле I2SDIV *2, если установлена единица (I2SDIV * 2)+1.

I2SDIV [7:0](I2S Linear prescaler) — битовое поле с помощью которого задается делитель. Запрещенные значения для него 0 и 1.

Инициализация из рабочего проекта в котором МК работает в режиме Slave - receive.

void I2S2_Init(void)
{
	/*
			WS  -> PB12
			CLK -> PB13
			SD  -> PB15
	*/
	
	//включаем тактирование порта и SPI
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
	RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
	
	//включаем тактирование I2S от PLL
	RCC->CFGR |= RCC_CFGR_I2SSRC;
	
	//альтернативная ф-ция push pull с подтяжкой к земле, 50 MHz
	GPIOB->MODER |= GPIO_MODER_MODER12_1 | GPIO_MODER_MODER13_1 | GPIO_MODER_MODER15_1;
	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR12_0 | GPIO_PUPDR_PUPDR13_0 | GPIO_PUPDR_PUPDR15_0;
	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12 | GPIO_OSPEEDER_OSPEEDR13 | GPIO_OSPEEDER_OSPEEDR15; 
	 
        //назначаем выводам альтернативную функцию 
        GPIOB->AFR[1] |= (0x05<<4*4);
	GPIOB->AFR[1] |= (0x05<<5*4);
	GPIOB->AFR[1] |= (0x05<<7*4);
      
        SPI2->I2SCFGR |= SPI_I2SCFGR_I2SMOD;//выбираем режим I2S
	SPI2->I2SCFGR |= SPI_I2SCFGR_I2SCFG_0;//Slave - receive
	SPI2->I2SCFGR &= ~SPI_I2SCFGR_CKPOL;//низкий уровень во время ожидания на выводе CLK
	SPI2->I2SCFGR &= ~SPI_I2SCFGR_I2SSTD;//I2S Philips
	SPI2->I2SCFGR |= SPI_I2SCFGR_DATLEN_0;//данные 24 бита
	SPI2->I2SCFGR |= SPI_I2SCFGR_CHLEN;//длина пакета 32 бита
	//SPI2->CR2 |= SPI_CR2_RXDMAEN;//DMA
        SPI2->I2SCFGR |= SPI_I2SCFGR_I2SE;//включаем I2S
}


Если запустить этот код, то модуль включится, но данные в регистре DR будут подпорчены. Для решения этого вопроса, необходимо обратиться к Errata sheet, в котором написано, что в нашем случае, включать I2S необходимо когда линия WS находится в высоком состоянии.

The I2S peripheral must be enabled when the external master sets the WS line at:
• High level when the I2S protocol is selected.
• Low level when the LSB or MSB-justified mode is selected.


Сделать это можно, разрешив внешнее прерывание, на ножке WS.

void WS_EXTI_Init(void)
{
     //выбор порта и пина для внешнего прерываниz
     SYSCFG->EXTICR [3] |= SYSCFG_EXTICR4_EXTI12_PB;
     //по возрастающему фронту
     EXTI->RTSR |= EXTI_RTSR_TR12;
     //устанавливаем маску
     EXTI->IMR |= EXTI_IMR_MR12;
     //разрешаем прерывания  EXTI5
     NVIC_EnableIRQ(EXTI15_10_IRQn);
     //NVIC_SetPriority(EXTI15_10_IRQn,15);
}	


И уже в прерывании включать модуль.

void EXTI15_10_IRQHandler(void)
{
       SPI2->I2SCFGR |= SPI_I2SCFGR_I2SE;//включаем I2S

	EXTI->IMR &= ~EXTI_IMR_MR12;
	EXTI->PR |= EXTI_PR_PR12;//reset interrupt flag
	EXTI->PR |= EXTI_PR_PR12;//reset interrupt flag
}	
Похожие статьи
комментарии
0