extern void init_i2s(const i2s_config *cfg, const i2s_instance *inst, i2s_sample_callback *callback) { uint32_t base = inst->i2si_base_address; // Just handle one case for now. assert(cfg->i2sc_sample_frequency == 44100); assert(cfg->i2sc_mode == I2SM_MASTER_TX); assert(cfg->i2sc_standard == I2SS_LSB); assert(cfg->i2sc_data_format == I2SF_16); assert(cfg->i2sc_mclk_output == I2SM_ENABLED); assert(cfg->i2sc_cpol == I2SC_CPOL_HIGH); assert(cfg->i2sc_clock_source == I2SC_PLL); assert(cfg->i2sc_full_duplex == false); switch (base) { case SPI2_BASE: spi2_callback = callback; spi2_left_right = I2SC_LEFT; break; case SPI3_BASE: spi3_callback = callback; spi3_left_right = I2SC_LEFT; break; default: assert(false && "i2s: unknown bad address"); } // Enable clock. rcc_periph_clock_enable(RCC_SPI2); // Enable GPIO pins. size_t pin_count = 3 + !!cfg->i2sc_mclk_output + !!cfg->i2sc_full_duplex; gpio_init_pins(cfg->i2sc_gpio_pins, pin_count); // Enable interrupt. nvic_enable_irq(NVIC_SPI2_IRQ); SPI_I2SCFGR(base) = 0; RCC_PLLI2SCFGR = PLLI2S_N_VALUE << RCC_PLLI2SCFGR_PLLI2SN_SHIFT | PLLI2S_R_VALUE << RCC_PLLI2SCFGR_PLLI2SR_SHIFT; SPI_I2SPR(base) = SPI_I2SPR_MCKOE | I2SPR_ODD_VALUE | I2SPR_I2SDIV_VALUE; SPI_I2SCFGR(base) = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT << SPI_I2SCFGR_I2SCFG_LSB | SPI_I2SCFGR_I2SSTD_I2S_PHILIPS << SPI_I2SCFGR_I2SSTD_LSB | SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_DATLEN_16BIT << SPI_I2SCFGR_DATLEN_LSB; SPI_CR2(base) |= SPI_CR2_TXEIE; // Start the I2S PLL. RCC_CR |= RCC_CR_PLLI2SON; // Enable I2S. SPI_I2SCFGR(base) |= SPI_I2SCFGR_I2SE; }
void codecInit(void) { memset(adcBuffer, 0xaa, sizeof(adcBuffer)); // I2S2 alternate function mapping gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15); gpio_set_af(GPIOB, GPIO_AF5, GPIO12 | GPIO13 | GPIO15); gpio_set_af(GPIOB, GPIO_AF6, GPIO14); // I2S2ext_SD (I2S receive) gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6); gpio_set_af(GPIOC, GPIO_AF5, GPIO6); // MCLK gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO12 | GPIO13 | GPIO15); gpio_set_output_options(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO6); // Set up SPI1 spi_reset(SPI1); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_256, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); spi_set_nss_high(SPI1); spi_enable_software_slave_management(SPI1); spi_enable(SPI1); // SPI1 alternate function mapping, set CSB signal high output gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); gpio_set(GPIOA, GPIO4); gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); codecConfig(); // Set up I2S for 48kHz 16-bit stereo. // The input to the PLLI2S is 1MHz. Division factors are from // table 126 in the data sheet. // // This gives us 1.536MHz SCLK = 16 bits * 2 channels * 48000 Hz // and 12.288 MHz MCLK = 256 * 48000 Hz. // With this PLL configuration the actual sampling frequency // is nominally 47991 Hz. spi_reset(SPI2); RCC_PLLI2SCFGR = (3 << 28) | (258 << 6); RCC_CR |= RCC_CR_PLLI2SON; while (!(RCC_CR & RCC_CR_PLLI2SRDY)); const unsigned i2sdiv = 3; SPI_I2SPR(SPI2) = SPI_I2SPR_MCKOE | SPI_I2SPR_ODD | i2sdiv; SPI_I2SCFGR(SPI2) |= SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT << SPI_I2SCFGR_I2SCFG_LSB); SPI_I2SCFGR(I2S2_EXT_BASE) = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_SLAVE_RECEIVE << SPI_I2SCFGR_I2SCFG_LSB); // Configure the DMA engine to stream data to the DAC. dma_stream_reset(DMA1, DAC_DMA_STREAM); dma_set_peripheral_address(DMA1, DAC_DMA_STREAM, (intptr_t)&SPI_DR(SPI2)); dma_set_memory_address(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[0]); dma_set_memory_address_1(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[1]); dma_set_number_of_data(DMA1, DAC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, DAC_DMA_STREAM, DAC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, DAC_DMA_STREAM, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); dma_set_memory_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, DAC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, DAC_DMA_STREAM); dma_enable_stream(DMA1, DAC_DMA_STREAM); // Configure the DMA engine to stream data from the ADC. dma_stream_reset(DMA1, ADC_DMA_STREAM); dma_set_peripheral_address(DMA1, ADC_DMA_STREAM, (intptr_t)&SPI_DR(I2S2_EXT_BASE)); dma_set_memory_address(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[0]); dma_set_memory_address_1(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[1]); dma_set_number_of_data(DMA1, ADC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, ADC_DMA_STREAM, ADC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, ADC_DMA_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); dma_set_memory_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, ADC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, ADC_DMA_STREAM); dma_enable_stream(DMA1, ADC_DMA_STREAM); dma_enable_transfer_complete_interrupt(DMA1, ADC_DMA_STREAM); nvic_enable_irq(NVIC_DMA1_STREAM3_IRQ); nvic_set_priority(NVIC_DMA1_STREAM3_IRQ, 0x80); // 0 is most urgent // Start transmitting data spi_enable_rx_dma(I2S2_EXT_BASE); spi_enable_tx_dma(SPI2); }