/** * intel_mid_i2s_open - reserve and start a SSP depending of it's usage * @usage : select which ssp i2s you need by giving usage (BT,MODEM...) * @ps_settings : hardware settings to configure the SSP module * * May sleep (driver_find_device) : no lock permitted when called. * * Output parameters * handle : handle of the selected SSP, or NULL if not found */ struct intel_mid_i2s_hdl *intel_mid_i2s_open(enum intel_mid_i2s_ssp_usage usage, const struct intel_mid_i2s_settings *ps_settings) { struct pci_dev *pdev; struct intel_mid_i2s_hdl *drv_data = NULL; struct device *found_device = NULL; pr_debug("%s : open called,searching for device with usage=%x !\n", DRIVER_NAME, usage); found_device = driver_find_device(&(intel_mid_i2s_driver.driver), NULL, &usage, check_device); if (!found_device) { pr_debug("%s : open can not found with usage=0x%02X\n", DRIVER_NAME, (int)usage); return NULL; } pdev = to_pci_dev(found_device); drv_data = pci_get_drvdata(pdev); drv_data->current_settings = *ps_settings; if (!drv_data) { dev_err(found_device, "no drv_data in open pdev=%p\n", pdev); put_device(found_device); return NULL; } mutex_lock(&drv_data->mutex); dev_dbg(found_device, "Open found pdevice=0x%p\n", pdev); /* pm_runtime */ pm_runtime_get_sync(&drv_data->pdev->dev); /* dmac1 is already set during probe */ if (i2s_dma_start(drv_data) != 0) { dev_err(found_device, "Can not start DMA\n"); goto open_error; } /* if we restart after stop without suspend, we start ssp faster */ set_ssp_i2s_hw(drv_data, ps_settings); drv_data->mask_sr = ((SSSR_BCE_MASK << SSSR_BCE_SHIFT) | (SSSR_EOC_MASK << SSSR_EOC_SHIFT) | (SSSR_ROR_MASK << SSSR_ROR_SHIFT) | (SSSR_TUR_MASK << SSSR_TUR_SHIFT) | (SSSR_TINT_MASK << SSSR_TINT_SHIFT) | (SSSR_PINT_MASK << SSSR_PINT_SHIFT)); if (test_bit(I2S_PORT_CLOSING, &drv_data->flags)) { dev_err(&drv_data->pdev->dev, "Opening a closing I2S!"); goto open_error; } /* there is no need to "wake up" as we can not close an opening i2s */ clear_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags); clear_bit(I2S_PORT_READ_BUSY, &drv_data->flags); mutex_unlock(&drv_data->mutex); return drv_data; open_error: pm_runtime_put(&drv_data->pdev->dev); put_device(found_device); mutex_unlock(&drv_data->mutex); return NULL; }
void ws2812_i2s_init(uint32_t pixels_number) { dma_buffer_size = pixels_number * DMA_PIXEL_SIZE; dma_block_list_size = dma_buffer_size / MAX_DMA_BLOCK_SIZE; if (dma_buffer_size % MAX_DMA_BLOCK_SIZE) { dma_block_list_size += 1; } dma_block_list_size += 2; // zero block and stop block debug("allocating %d dma blocks\n", dma_block_list_size); dma_block_list = (dma_descriptor_t*)malloc( dma_block_list_size * sizeof(dma_descriptor_t)); debug("allocating %d bytes for DMA buffer\n", dma_buffer_size); dma_buffer = malloc(dma_buffer_size); memset(dma_buffer, 0xFA, dma_buffer_size); init_descriptors_list(dma_buffer, dma_buffer_size); i2s_clock_div_t clock_div = i2s_get_clock_div(3333333); i2s_pins_t i2s_pins = {.data = true, .clock = false, .ws = false}; debug("i2s clock dividers, bclk=%d, clkm=%d\n", clock_div.bclk_div, clock_div.clkm_div); i2s_dma_init(dma_isr_handler, clock_div, i2s_pins); } const IRAM_DATA int16_t bitpatterns[16] = { 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, }; void ws2812_i2s_update(ws2812_pixel_t *pixels) { while (i2s_dma_processing) {}; uint16_t *p_dma_buf = dma_buffer; for (uint32_t i = 0; i < (dma_buffer_size / DMA_PIXEL_SIZE); i++) { // green *p_dma_buf++ = bitpatterns[pixels[i].green & 0x0F]; *p_dma_buf++ = bitpatterns[pixels[i].green >> 4]; // red *p_dma_buf++ = bitpatterns[pixels[i].red & 0x0F]; *p_dma_buf++ = bitpatterns[pixels[i].red >> 4]; // blue *p_dma_buf++ = bitpatterns[pixels[i].blue & 0x0F]; *p_dma_buf++ = bitpatterns[pixels[i].blue >> 4]; } i2s_dma_processing = true; i2s_dma_start(dma_block_list); }
void play_task(void *pvParameters) { esp_spiffs_init(); if (esp_spiffs_mount() != SPIFFS_OK) { printf("Error mount SPIFFS\n"); } int fd = open("sample.wav", O_RDONLY); if (fd < 0) { printf("Error opening file\n"); return; } dumb_wav_header_t wav_header; read(fd, (void*)&wav_header, sizeof(wav_header)); printf("Number of channels: %d\n", wav_header.num_channels); printf("Bits per sample: %d\n", wav_header.bits_per_sample); printf("Sample rate: %d\n", wav_header.sample_rate); printf("Data size: %d\n", wav_header.data_size); if (wav_header.bits_per_sample != 16) { printf("Only 16 bit per sample is supported\n"); return; } if (wav_header.num_channels != 2) { printf("Only 2 channels is supported\n"); return; } i2s_clock_div_t clock_div = i2s_get_clock_div( wav_header.sample_rate * 2 * 16); printf("i2s clock dividers, bclk=%d, clkm=%d\n", clock_div.bclk_div, clock_div.clkm_div); i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true}; i2s_dma_init(dma_isr_handler, clock_div, i2s_pins); while (1) { init_descriptors_list(); i2s_dma_start(dma_block_list); lseek(fd, sizeof(dumb_wav_header_t), SEEK_SET); while (play_data(fd)) {}; i2s_dma_stop(); vQueueDelete(dma_queue); printf("underrun counter: %d\n", underrun_counter); vTaskDelay(1000 / portTICK_PERIOD_MS); } close(fd); } void user_init(void) { uart_set_baud(0, 115200); xTaskCreate(play_task, "test_task", 1024, NULL, 2, NULL); }