rework parts of I2S
This commit is contained in:
parent
5e64def682
commit
daa5848431
|
@ -1,5 +1,7 @@
|
||||||
// Module for interfacing with i2s hardware
|
// Module for interfacing with i2s hardware
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
|
@ -19,106 +21,211 @@
|
||||||
#define I2S_CHECK_ID(id) if(id >= MAX_I2C_NUM) luaL_error( L, "i2s not exists" )
|
#define I2S_CHECK_ID(id) if(id >= MAX_I2C_NUM) luaL_error( L, "i2s not exists" )
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
xTaskHandle taskHandle;
|
int ref;
|
||||||
QueueHandle_t *event_queue;
|
const char *data;
|
||||||
int event_cb;
|
size_t len;
|
||||||
} i2s_status_t;
|
} i2s_tx_data_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
i2s_event_t event;
|
struct {
|
||||||
i2s_status_t* status;
|
xTaskHandle taskHandle;
|
||||||
} i2s_event_post_type;
|
QueueHandle_t queue;
|
||||||
|
} tx;
|
||||||
|
struct {
|
||||||
|
xTaskHandle taskHandle;
|
||||||
|
QueueHandle_t queue;
|
||||||
|
} rx;
|
||||||
|
int cb;
|
||||||
|
int i2s_bits_per_sample, data_bits_per_sample;
|
||||||
|
} i2s_status_t;
|
||||||
|
|
||||||
static task_handle_t i2s_event_task_id;
|
static task_handle_t i2s_tx_task_id, i2s_rx_task_id, i2s_disposal_task_id;
|
||||||
|
|
||||||
static i2s_status_t i2s_status[MAX_I2C_NUM];
|
static i2s_status_t i2s_status[MAX_I2C_NUM];
|
||||||
|
|
||||||
// LUA
|
// LUA
|
||||||
static void i2s_event_task( task_param_t param, task_prio_t prio ) {
|
static void i2s_tx_task( task_param_t param, task_prio_t prio ) {
|
||||||
i2s_event_post_type *post = (i2s_event_post_type *)param;
|
int i2s_id = (int)param;
|
||||||
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
|
|
||||||
lua_State *L = lua_getstate();
|
if (is->cb != LUA_NOREF) {
|
||||||
int event_cb = post->status->event_cb;
|
lua_State *L = lua_getstate();
|
||||||
if(event_cb == LUA_NOREF) {
|
lua_rawgeti(L, LUA_REGISTRYINDEX, is->cb);
|
||||||
free( post );
|
lua_pushinteger( L, i2s_id );
|
||||||
return;
|
lua_pushstring( L, "tx" );
|
||||||
|
lua_call( L, 2, 0 );
|
||||||
}
|
}
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, event_cb);
|
}
|
||||||
if(post->event.type == I2S_EVENT_TX_DONE)
|
|
||||||
lua_pushstring(L, "sent");
|
static void i2s_rx_task( task_param_t param, task_prio_t prio ) {
|
||||||
else if(post->event.type == I2S_EVENT_RX_DONE)
|
int i2s_id = (int)param;
|
||||||
lua_pushstring(L, "data");
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
else
|
|
||||||
lua_pushstring(L, "error");
|
if (is->cb != LUA_NOREF) {
|
||||||
lua_pushinteger(L, post->event.size);
|
lua_State *L = lua_getstate();
|
||||||
free( post );
|
lua_rawgeti(L, LUA_REGISTRYINDEX, is->cb);
|
||||||
lua_call(L, 2, 0);
|
lua_pushinteger( L, i2s_id );
|
||||||
|
lua_pushstring( L, "rx" );
|
||||||
|
lua_call( L, 2, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2s_disposal_task( task_param_t param, task_prio_t prio ) {
|
||||||
|
lua_State *L = lua_getstate();
|
||||||
|
int ref = (int)param;
|
||||||
|
|
||||||
|
luaL_unref( L, LUA_REGISTRYINDEX, ref );
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTOS
|
// RTOS
|
||||||
static void task_I2S( void *pvParameters ){
|
static void task_I2S_rx( void *pvParameters ) {
|
||||||
i2s_status_t* is = (i2s_status_t*)pvParameters;
|
int i2s_id = (int)pvParameters;
|
||||||
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
i2s_event_t event;
|
|
||||||
|
|
||||||
for (;;){
|
i2s_event_t i2s_event;
|
||||||
if( xQueueReceive( is->event_queue, &event, 3 * portTICK_PERIOD_MS ) == pdTRUE ){
|
|
||||||
i2s_event_post_type *post = (i2s_event_post_type *)malloc( sizeof( i2s_event_post_type ) );
|
for (;;) {
|
||||||
post->status = is;
|
// process I2S RX events
|
||||||
memcpy(&(post->event), &event, sizeof(i2s_event_t));
|
xQueueReceive( is->rx.queue, &i2s_event, portMAX_DELAY );
|
||||||
task_post_high( i2s_event_task_id, (task_param_t)post );
|
if (i2s_event.type == I2S_EVENT_RX_DONE) {
|
||||||
|
task_post_high( i2s_rx_task_id, i2s_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void task_I2S_tx( void *pvParameters ) {
|
||||||
|
int i2s_id = (int)pvParameters;
|
||||||
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
|
|
||||||
|
i2s_tx_data_t tx_data;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// request new TX data
|
||||||
|
task_post_high( i2s_tx_task_id, i2s_id );
|
||||||
|
|
||||||
|
// get TX data from Lua task
|
||||||
|
xQueueReceive( is->tx.queue, &tx_data, portMAX_DELAY );
|
||||||
|
|
||||||
|
// write TX data to I2S, note that this call might block
|
||||||
|
size_t dummy;
|
||||||
|
if (is->data_bits_per_sample == is->i2s_bits_per_sample) {
|
||||||
|
i2s_write( i2s_id, tx_data.data, tx_data.len, &dummy, portMAX_DELAY );
|
||||||
|
} else {
|
||||||
|
i2s_write_expand( i2s_id, tx_data.data, tx_data.len, is->data_bits_per_sample, is->i2s_bits_per_sample, &dummy, portMAX_DELAY );
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify Lua to dispose object
|
||||||
|
task_post_low( i2s_disposal_task_id, tx_data.ref );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lua: start( i2s_id, {}, callback )
|
// Lua: start( i2s_id, {}, callback )
|
||||||
static int node_i2s_start( lua_State *L )
|
static int node_i2s_start( lua_State *L )
|
||||||
{
|
{
|
||||||
int i2s_id = luaL_checkinteger( L, 1 );
|
int i2s_id = luaL_checkinteger( L, 1 );
|
||||||
I2S_CHECK_ID( i2s_id );
|
I2S_CHECK_ID( i2s_id );
|
||||||
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
|
|
||||||
|
int top = lua_gettop( L );
|
||||||
|
|
||||||
luaL_checkanytable (L, 2);
|
luaL_checkanytable (L, 2);
|
||||||
|
|
||||||
i2s_config_t i2s_config;
|
i2s_config_t i2s_config;
|
||||||
|
memset( &i2s_config, 0, sizeof( i2s_config ) );
|
||||||
i2s_pin_config_t pin_config;
|
i2s_pin_config_t pin_config;
|
||||||
|
memset( &pin_config, 0, sizeof( pin_config ) );
|
||||||
|
|
||||||
lua_getfield (L, 2, "mode");
|
lua_getfield (L, 2, "mode");
|
||||||
i2s_config.mode = luaL_optint(L, -1, I2S_MODE_MASTER | I2S_MODE_TX);
|
i2s_config.mode = luaL_optint(L, -1, I2S_MODE_MASTER | I2S_MODE_TX);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "rate");
|
lua_getfield (L, 2, "rate");
|
||||||
i2s_config.sample_rate = luaL_optint(L, -1, 44100);
|
i2s_config.sample_rate = luaL_optint(L, -1, 44100);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "bits");
|
lua_getfield (L, 2, "bits");
|
||||||
i2s_config.bits_per_sample = 16;
|
is->data_bits_per_sample = luaL_optint(L, -1, 16);
|
||||||
|
is->i2s_bits_per_sample = is->data_bits_per_sample < I2S_BITS_PER_SAMPLE_16BIT ? I2S_BITS_PER_SAMPLE_16BIT : is->data_bits_per_sample;
|
||||||
|
i2s_config.bits_per_sample = is->i2s_bits_per_sample;
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "channel");
|
lua_getfield (L, 2, "channel");
|
||||||
i2s_config.channel_format = luaL_optint(L, -1, I2S_CHANNEL_FMT_RIGHT_LEFT);
|
i2s_config.channel_format = luaL_optint(L, -1, I2S_CHANNEL_FMT_RIGHT_LEFT);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "format");
|
lua_getfield (L, 2, "format");
|
||||||
i2s_config.communication_format = luaL_optint(L, -1, I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB);
|
i2s_config.communication_format = luaL_optint(L, -1, I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "buffer_count");
|
lua_getfield (L, 2, "buffer_count");
|
||||||
i2s_config.dma_buf_count = luaL_optint(L, -1, 2);
|
i2s_config.dma_buf_count = luaL_optint(L, -1, 2);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "buffer_len");
|
lua_getfield (L, 2, "buffer_len");
|
||||||
i2s_config.dma_buf_len = luaL_optint(L, -1, i2s_config.sample_rate / 100);
|
i2s_config.dma_buf_len = luaL_optint(L, -1, i2s_config.sample_rate / 100);
|
||||||
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2;
|
//
|
||||||
|
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM;
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "bck_pin");
|
lua_getfield (L, 2, "bck_pin");
|
||||||
pin_config.bck_io_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
pin_config.bck_io_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "ws_pin");
|
lua_getfield (L, 2, "ws_pin");
|
||||||
pin_config.ws_io_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
pin_config.ws_io_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "data_out_pin");
|
lua_getfield (L, 2, "data_out_pin");
|
||||||
pin_config.data_out_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
pin_config.data_out_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
||||||
|
//
|
||||||
lua_getfield (L, 2, "data_in_pin");
|
lua_getfield (L, 2, "data_in_pin");
|
||||||
pin_config.data_in_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
pin_config.data_in_num = luaL_optint(L, -1, I2S_PIN_NO_CHANGE);
|
||||||
|
//
|
||||||
lua_settop(L, 3);
|
lua_getfield(L, 2, "dac_mode");
|
||||||
i2s_status[i2s_id].event_cb = luaL_ref(L, LUA_REGISTRYINDEX);
|
i2s_dac_mode_t dac_mode = luaL_optint(L, -1, I2S_DAC_CHANNEL_DISABLE);
|
||||||
|
//
|
||||||
|
lua_getfield(L, 2, "adc1_channel");
|
||||||
|
adc1_channel_t adc1_channel = luaL_optint(L, -1, ADC1_CHANNEL_MAX);
|
||||||
|
|
||||||
esp_err_t err = i2s_driver_install(i2s_id, &i2s_config, i2s_config.dma_buf_count, &i2s_status[i2s_id].event_queue);
|
// handle optional callback functions TX and RX
|
||||||
if(err != ESP_OK)
|
lua_settop( L, top );
|
||||||
|
if (lua_isfunction( L, 3 )) {
|
||||||
|
lua_pushvalue( L, 3 );
|
||||||
|
is->cb = luaL_ref( L, LUA_REGISTRYINDEX );
|
||||||
|
} else {
|
||||||
|
is->cb = LUA_NOREF;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err;
|
||||||
|
if (i2s_config.mode & I2S_MODE_RX) {
|
||||||
|
err = i2s_driver_install(i2s_id, &i2s_config, i2s_config.dma_buf_count, &is->rx.queue);
|
||||||
|
} else {
|
||||||
|
err = i2s_driver_install(i2s_id, &i2s_config, i2s_config.dma_buf_count, NULL);
|
||||||
|
}
|
||||||
|
if (err != ESP_OK)
|
||||||
luaL_error( L, "i2s can not start" );
|
luaL_error( L, "i2s can not start" );
|
||||||
i2s_set_pin(i2s_id, &pin_config);
|
|
||||||
|
|
||||||
char pcName[5];
|
if (dac_mode != I2S_DAC_CHANNEL_DISABLE) {
|
||||||
snprintf( pcName, 5, "I2S%d", i2s_id );
|
if (i2s_set_dac_mode( dac_mode ) != ESP_OK)
|
||||||
pcName[4] = '\0';
|
luaL_error( L, "error setting dac mode" );
|
||||||
xTaskCreate(task_I2S, pcName, 2048, &i2s_status[i2s_id], ESP_TASK_MAIN_PRIO + 1, &i2s_status[i2s_id].taskHandle);
|
}
|
||||||
|
if (adc1_channel != ADC1_CHANNEL_MAX) {
|
||||||
|
if (i2s_set_adc_mode( ADC_UNIT_1, adc1_channel ) != ESP_OK)
|
||||||
|
luaL_error( L, "error setting adc1 mode" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2s_set_pin(i2s_id, &pin_config) != ESP_OK)
|
||||||
|
luaL_error( L, "error setting pins" );
|
||||||
|
|
||||||
|
|
||||||
|
if (i2s_config.mode & I2S_MODE_TX) {
|
||||||
|
// prepare TX task
|
||||||
|
char pcName[8];
|
||||||
|
snprintf( pcName, 8, "I2S_tx_%d", i2s_id );
|
||||||
|
pcName[7] = '\0';
|
||||||
|
if ((is->tx.queue = xQueueCreate( 2, sizeof( i2s_tx_data_t ) )) == NULL)
|
||||||
|
return luaL_error( L, "cannot create queue" );
|
||||||
|
xTaskCreate(task_I2S_tx, pcName, 2048, (void *)i2s_id, ESP_TASK_MAIN_PRIO + 1, &is->tx.taskHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2s_config.mode & I2S_MODE_RX) {
|
||||||
|
// prepare RX task
|
||||||
|
char pcName[8];
|
||||||
|
snprintf( pcName, 8, "I2S_rx_%d", i2s_id );
|
||||||
|
pcName[7] = '\0';
|
||||||
|
xTaskCreate(task_I2S_rx, pcName, 1024, (void *)i2s_id, ESP_TASK_MAIN_PRIO + 1, &is->rx.taskHandle);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -128,20 +235,30 @@ static int node_i2s_stop( lua_State *L )
|
||||||
{
|
{
|
||||||
int i2s_id = luaL_checkinteger( L, 1 );
|
int i2s_id = luaL_checkinteger( L, 1 );
|
||||||
I2S_CHECK_ID( i2s_id );
|
I2S_CHECK_ID( i2s_id );
|
||||||
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
|
|
||||||
i2s_driver_uninstall(i2s_id);
|
i2s_driver_uninstall(i2s_id);
|
||||||
i2s_status[i2s_id].event_queue = NULL;
|
|
||||||
|
if (is->tx.taskHandle != NULL) {
|
||||||
if(i2s_status[i2s_id].taskHandle != NULL) {
|
vTaskDelete( is->tx.taskHandle );
|
||||||
vTaskDelete(i2s_status[i2s_id].taskHandle);
|
is->tx.taskHandle = NULL;
|
||||||
i2s_status[i2s_id].taskHandle = NULL;
|
|
||||||
}
|
}
|
||||||
|
if (is->tx.queue != NULL) {
|
||||||
if(i2s_status[i2s_id].event_cb != LUA_NOREF) {
|
vQueueDelete( is->tx.queue );
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, i2s_status[i2s_id].event_cb);
|
is->tx.queue = NULL;
|
||||||
i2s_status[i2s_id].event_cb = LUA_NOREF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is->rx.taskHandle != NULL) {
|
||||||
|
vTaskDelete( is->rx.taskHandle );
|
||||||
|
is->rx.taskHandle = NULL;
|
||||||
|
}
|
||||||
|
// the rx queue is created and destroyed by the I2S driver
|
||||||
|
|
||||||
|
if (is->cb != LUA_NOREF) {
|
||||||
|
luaL_unref( L, LUA_REGISTRYINDEX, is->cb );
|
||||||
|
is->cb = LUA_NOREF;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,80 +267,86 @@ static int node_i2s_read( lua_State *L )
|
||||||
{
|
{
|
||||||
int i2s_id = luaL_checkinteger( L, 1 );
|
int i2s_id = luaL_checkinteger( L, 1 );
|
||||||
I2S_CHECK_ID( i2s_id );
|
I2S_CHECK_ID( i2s_id );
|
||||||
|
|
||||||
size_t bytes = luaL_checkinteger( L, 2 );
|
size_t bytes = luaL_checkinteger( L, 2 );
|
||||||
int wait_ms = luaL_optint(L, 3, 0);
|
//int wait_ms = luaL_optint(L, 3, 0);
|
||||||
char * data = luaM_malloc( L, bytes );
|
char * data = luaM_malloc( L, bytes );
|
||||||
size_t read = i2s_read_bytes(i2s_id, data, bytes, wait_ms / portTICK_RATE_MS);
|
size_t read = 0;
|
||||||
lua_pushlstring(L, data, read);
|
//read = i2s_read_bytes(i2s_id, data, bytes, wait_ms / portTICK_RATE_MS);
|
||||||
|
lua_pushlstring(L, data, read);
|
||||||
luaM_free(L, data);
|
luaM_free(L, data);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua: write( i2s_id, data[, wait_ms] )
|
// Lua: write( i2s_id, data )
|
||||||
static int node_i2s_write( lua_State *L )
|
static int node_i2s_write( lua_State *L )
|
||||||
{
|
{
|
||||||
int i2s_id = luaL_checkinteger( L, 1 );
|
int stack = 0;
|
||||||
I2S_CHECK_ID( i2s_id );
|
|
||||||
|
|
||||||
size_t bytes;
|
|
||||||
char *data;
|
|
||||||
if( lua_istable( L, 2 ) ) {
|
|
||||||
bytes = lua_objlen( L, 2 );
|
|
||||||
data = (char *)luaM_malloc( L, bytes );
|
|
||||||
for( int i = 0; i < bytes; i ++ ) {
|
|
||||||
lua_rawgeti( L, 2, i + 1 );
|
|
||||||
data[i] = (uint8_t)luaL_checkinteger( L, -1 );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = (char *) luaL_checklstring(L, 2, &bytes);
|
|
||||||
}
|
|
||||||
int wait_ms = luaL_optint(L, 3, 0);
|
|
||||||
size_t wrote = i2s_write_bytes(i2s_id, data, bytes, wait_ms / portTICK_RATE_MS);
|
|
||||||
if( lua_istable( L, 2 ) )
|
|
||||||
luaM_free(L, data);
|
|
||||||
lua_pushinteger( L, ( lua_Integer ) wrote );
|
|
||||||
|
|
||||||
return 1;
|
int i2s_id = luaL_checkinteger( L, ++stack );
|
||||||
|
I2S_CHECK_ID( i2s_id );
|
||||||
|
|
||||||
|
i2s_tx_data_t tx_data;
|
||||||
|
tx_data.data = (const char *)luaL_checklstring( L, ++stack, &tx_data.len );
|
||||||
|
lua_pushvalue( L, stack );
|
||||||
|
tx_data.ref = luaL_ref( L, LUA_REGISTRYINDEX );
|
||||||
|
|
||||||
|
// post this to the TX task
|
||||||
|
xQueueSendToBack( i2s_status[i2s_id].tx.queue, &tx_data, portMAX_DELAY );
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module function map
|
// Module function map
|
||||||
static const LUA_REG_TYPE i2s_map[] =
|
static const LUA_REG_TYPE i2s_map[] =
|
||||||
{
|
{
|
||||||
{ LSTRKEY( "start" ), LFUNCVAL( node_i2s_start ) },
|
{ LSTRKEY( "start" ), LFUNCVAL( node_i2s_start ) },
|
||||||
{ LSTRKEY( "stop" ), LFUNCVAL( node_i2s_stop ) },
|
{ LSTRKEY( "stop" ), LFUNCVAL( node_i2s_stop ) },
|
||||||
{ LSTRKEY( "read" ), LFUNCVAL( node_i2s_read ) },
|
{ LSTRKEY( "read" ), LFUNCVAL( node_i2s_read ) },
|
||||||
{ LSTRKEY( "write" ), LFUNCVAL( node_i2s_write ) },
|
{ LSTRKEY( "write" ), LFUNCVAL( node_i2s_write ) },
|
||||||
{ LSTRKEY( "FORMAT_I2S" ), LNUMVAL( I2S_COMM_FORMAT_I2S ) },
|
|
||||||
{ LSTRKEY( "FORMAT_I2S_MSB" ), LNUMVAL( I2S_COMM_FORMAT_I2S_MSB ) },
|
{ LSTRKEY( "FORMAT_I2S" ), LNUMVAL( I2S_COMM_FORMAT_I2S ) },
|
||||||
{ LSTRKEY( "FORMAT_I2S_LSB" ), LNUMVAL( I2S_COMM_FORMAT_I2S_LSB ) },
|
{ LSTRKEY( "FORMAT_I2S_MSB" ), LNUMVAL( I2S_COMM_FORMAT_I2S_MSB ) },
|
||||||
{ LSTRKEY( "FORMAT_PCM" ), LNUMVAL( I2S_COMM_FORMAT_PCM ) },
|
{ LSTRKEY( "FORMAT_I2S_LSB" ), LNUMVAL( I2S_COMM_FORMAT_I2S_LSB ) },
|
||||||
{ LSTRKEY( "FORMAT_PCM_SHORT" ), LNUMVAL( I2S_COMM_FORMAT_PCM_SHORT ) },
|
{ LSTRKEY( "FORMAT_PCM" ), LNUMVAL( I2S_COMM_FORMAT_PCM ) },
|
||||||
|
{ LSTRKEY( "FORMAT_PCM_SHORT" ), LNUMVAL( I2S_COMM_FORMAT_PCM_SHORT ) },
|
||||||
{ LSTRKEY( "FORMAT_PCM_LONG" ), LNUMVAL( I2S_COMM_FORMAT_PCM_LONG ) },
|
{ LSTRKEY( "FORMAT_PCM_LONG" ), LNUMVAL( I2S_COMM_FORMAT_PCM_LONG ) },
|
||||||
|
|
||||||
{ LSTRKEY( "CHANNEL_RIGHT_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_RIGHT_LEFT ) },
|
{ LSTRKEY( "CHANNEL_RIGHT_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_RIGHT_LEFT ) },
|
||||||
{ LSTRKEY( "CHANNEL_ALL_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_ALL_LEFT ) },
|
{ LSTRKEY( "CHANNEL_ALL_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_ALL_LEFT ) },
|
||||||
{ LSTRKEY( "CHANNEL_ONLY_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_ONLY_LEFT ) },
|
{ LSTRKEY( "CHANNEL_ONLY_LEFT" ), LNUMVAL( I2S_CHANNEL_FMT_ONLY_LEFT ) },
|
||||||
{ LSTRKEY( "CHANNEL_ALL_RIGHT" ), LNUMVAL( I2S_CHANNEL_FMT_ALL_RIGHT ) },
|
{ LSTRKEY( "CHANNEL_ALL_RIGHT" ), LNUMVAL( I2S_CHANNEL_FMT_ALL_RIGHT ) },
|
||||||
{ LSTRKEY( "CHANNEL_ONLY_RIGHT" ), LNUMVAL( I2S_CHANNEL_FMT_ONLY_RIGHT ) },
|
{ LSTRKEY( "CHANNEL_ONLY_RIGHT" ), LNUMVAL( I2S_CHANNEL_FMT_ONLY_RIGHT ) },
|
||||||
|
|
||||||
{ LSTRKEY( "MODE_MASTER" ), LNUMVAL( I2S_MODE_MASTER ) },
|
{ LSTRKEY( "MODE_MASTER" ), LNUMVAL( I2S_MODE_MASTER ) },
|
||||||
{ LSTRKEY( "MODE_SLAVE" ), LNUMVAL( I2S_MODE_SLAVE ) },
|
{ LSTRKEY( "MODE_SLAVE" ), LNUMVAL( I2S_MODE_SLAVE ) },
|
||||||
{ LSTRKEY( "MODE_TX" ), LNUMVAL( I2S_MODE_TX ) },
|
{ LSTRKEY( "MODE_TX" ), LNUMVAL( I2S_MODE_TX ) },
|
||||||
{ LSTRKEY( "MODE_RX" ), LNUMVAL( I2S_MODE_RX ) },
|
{ LSTRKEY( "MODE_RX" ), LNUMVAL( I2S_MODE_RX ) },
|
||||||
{ LSTRKEY( "MODE_DAC_BUILT_IN" ), LNUMVAL( I2S_MODE_DAC_BUILT_IN ) },
|
{ LSTRKEY( "MODE_DAC_BUILT_IN" ), LNUMVAL( I2S_MODE_DAC_BUILT_IN ) },
|
||||||
|
{ LSTRKEY( "MODE_ADC_BUILT_IN" ), LNUMVAL( I2S_MODE_ADC_BUILT_IN ) },
|
||||||
|
{ LSTRKEY( "MODE_PDM" ), LNUMVAL( I2S_MODE_PDM ) },
|
||||||
|
|
||||||
|
{ LSTRKEY( "DAC_CHANNEL_DISABLE" ), LNUMVAL( I2S_DAC_CHANNEL_DISABLE ) },
|
||||||
|
{ LSTRKEY( "DAC_CHANNEL_RIGHT" ), LNUMVAL( I2S_DAC_CHANNEL_RIGHT_EN ) },
|
||||||
|
{ LSTRKEY( "DAC_CHANNEL_LEFT" ), LNUMVAL( I2S_DAC_CHANNEL_LEFT_EN ) },
|
||||||
|
{ LSTRKEY( "DAC_CHANNEL_BOTH" ), LNUMVAL( I2S_DAC_CHANNEL_BOTH_EN ) },
|
||||||
|
|
||||||
{ LNILKEY, LNILVAL }
|
{ LNILKEY, LNILVAL }
|
||||||
};
|
};
|
||||||
|
|
||||||
int luaopen_i2s( lua_State *L ) {
|
int luaopen_i2s( lua_State *L ) {
|
||||||
for(int i2s_id = 0; i2s_id < MAX_I2C_NUM; i2s_id++) {
|
for(int i2s_id = 0; i2s_id < MAX_I2C_NUM; i2s_id++) {
|
||||||
i2s_status[i2s_id].event_queue = NULL;
|
i2s_status_t *is = &i2s_status[i2s_id];
|
||||||
i2s_status[i2s_id].taskHandle = NULL;
|
is->tx.queue = NULL;
|
||||||
i2s_status[i2s_id].event_cb = LUA_NOREF;
|
is->tx.taskHandle = NULL;
|
||||||
|
is->rx.queue = NULL;
|
||||||
|
is->rx.taskHandle = NULL;
|
||||||
|
is->cb = LUA_NOREF;
|
||||||
}
|
}
|
||||||
i2s_event_task_id = task_get_id( i2s_event_task );
|
i2s_tx_task_id = task_get_id( i2s_tx_task );
|
||||||
|
i2s_rx_task_id = task_get_id( i2s_rx_task );
|
||||||
|
i2s_disposal_task_id = task_get_id( i2s_disposal_task );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,57 +1,71 @@
|
||||||
# I2S Module
|
# I2S Module
|
||||||
| Since | Origin / Contributor | Maintainer | Source |
|
| Since | Origin / Contributor | Maintainer | Source |
|
||||||
| :----- | :-------------------- | :---------- | :------ |
|
| :----- | :-------------------- | :---------- | :------ |
|
||||||
| 2017-04-29 | zelll | | [i2s.c](../../../components/modules/i2s.c)|
|
| 2017-04-29 | zelll | [Arnim Läuger](https://github.com/devsaurus) | [i2s.c](../../../components/modules/i2s.c)|
|
||||||
|
|
||||||
The I2S module provides access to the in-built two I2S controllers.
|
The I2S module provides access to the in-built two I2S controllers.
|
||||||
|
|
||||||
|
!!! note "DAC mode configuration"
|
||||||
|
DACs are only available for DAC built-in mode on I2S peripheral 0.
|
||||||
|
|
||||||
|
!!! note "ADC mode configuration"
|
||||||
|
Only ADC1 is available for ADC built-in mode.
|
||||||
|
|
||||||
## i2s.start()
|
## i2s.start()
|
||||||
Configuration and start I2S bus.
|
Configuration and start I2S bus.
|
||||||
|
|
||||||
#### Syntax
|
#### Syntax
|
||||||
```lua
|
```lua
|
||||||
i2s.start(i2s_num, cfg = {
|
i2s.start(i2s_num, cfg, cb)
|
||||||
mode = can.MODE_MASTER + can.MODE_TX,
|
|
||||||
rate = 44100,
|
|
||||||
bits = 16,
|
|
||||||
channel = i2s.CHANNEL_RIGHT_LEFT,
|
|
||||||
format = i2s.FORMAT_I2S + i2s.FORMAT_I2S_MSB,
|
|
||||||
buffer_count = 2,
|
|
||||||
buffer_len = 441,
|
|
||||||
bck_pin = 16,
|
|
||||||
ws_pin = 17,
|
|
||||||
data_out_pin = 18,
|
|
||||||
data_in_pin = -1
|
|
||||||
}, callback)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
- `i2s_num` `1` or `2`
|
- `i2s_num` I2S peripheral 0 or 1
|
||||||
- `cfg` configuration
|
- `cfg` table containing configuration data:
|
||||||
- `mode` combine of following constants `i2s.MODE_MASTER`, `i2s.MODE_SLAVE`, `i2s.MODE_TX`, `i2s.MODE_RX`, `i2s.MODE_DAC_BUILT_IN`. Default: `i2s.MODE_MASTER + i2s.MODE_TX`
|
- `mode` I2S work mode. Optional, defaults to `i2s.MODE_MASTER + i2s.MODE_TX` when omitted
|
||||||
- `rate` Audio sample rate, such as `44100`, `48000`, `16000`, `800`. Default: `44100`
|
- `i2s.MODE_MASTER`
|
||||||
- `bits` `32`, `24`, `16` or `8`. Default: `16`
|
- `i2s.MODE_SLAVE`
|
||||||
- `channel` One of following constants. Default: `i2s.CHANNEL_RIGHT_LEFT`
|
- `i2s.MODE_TX`
|
||||||
- `i2s.CHANNEL_RIGHT_LEFT`
|
- `i2s.MODE_RX`
|
||||||
|
- `i2s.MODE_DAC_BUILT_IN`
|
||||||
|
- `i2s.MODE_ADC_BUILT_IN`
|
||||||
|
- `i2s.MODE_PDM`
|
||||||
|
- `rate` audio sample rate. Optional, defauls to 44100 when omitted
|
||||||
|
- `bits` bits per sample. Optional, defaults to 16 when omitted
|
||||||
|
- `channel` channel format of I2S stream. Optional, defaults to `i2s.CHANNEL_RIGHT_LEFT` when omitted
|
||||||
|
- `i2s.CHANNEL_RIGHT_LEFT`
|
||||||
- `i2s.CHANNEL_ALL_LEFT`
|
- `i2s.CHANNEL_ALL_LEFT`
|
||||||
- `i2s.CHANNEL_ONLY_LEFT`
|
- `i2s.CHANNEL_ONLY_LEFT`
|
||||||
- `i2s.CHANNEL_ALL_RIGHT`
|
- `i2s.CHANNEL_ALL_RIGHT`
|
||||||
- `i2s.CHANNEL_ONLY_RIGHT`
|
- `i2s.CHANNEL_ONLY_RIGHT`
|
||||||
- `format` combine of following constants `i2s.FORMAT_I2S`, `i2s.FORMAT_I2S_MSB`, `i2s.FORMAT_I2S_LSB`, `i2s.FORMAT_PCM`, `i2s.FORMAT_PCM_SHORT`, `i2s.FORMAT_PCM_LONG`.
|
- `format` communicarion format. Optional, defaults to `i2s.FORMAT_I2S + i2s.FORMAT_I2S_MSB` when omitted
|
||||||
Default: `i2s.FORMAT_I2S + i2s.FORMAT_I2S_MSB`
|
- `i2s.FORMAT_I2S`
|
||||||
- `buffer_count` Buffer count. Default: 2
|
- `i2s.FORMAT_I2S_MSB`
|
||||||
- `buffer_len` Size of one buffer. Default: rate/100
|
- `i2s.FORMAT_I2S_LSB`
|
||||||
- `bck_pin` Clock pin. Default: `-1`
|
- `i2s.FORMAT_PCM`
|
||||||
- `ws_pin` WS pin. Default: `-1`
|
- `i2s.FORMAT_PCM_SHORT`
|
||||||
- `data_out_pin` Pin for data output. Default: `-1`
|
- `i2s.FORMAT_PCM_LONG`
|
||||||
- `data_in_pin` Pin for data input. Default: `-1`
|
- `buffer_count` number of dma buffers. Optional, defaults to 2 when omitted
|
||||||
- `callback` function called when i2s event occurs.
|
- `buffer_len` size of one dma buffer. Optional, defaults to rate/100
|
||||||
- `event` Event type, one of `sent`, `data`, `error`
|
- `bck_pin` clock pin, optional
|
||||||
- `size` bytes
|
- `ws_pin` WS pin, optional
|
||||||
|
- `data_out_pin` data output pin, optional
|
||||||
|
- `data_in_pin` data input pin, optional
|
||||||
|
- `dac_mode` DAC mode configuration. Optional, defaults to `i2s.DAC_CHANNEL_DISABLE` if omitted
|
||||||
|
- `i2s.DAC_CHANNEL_DISABLE`
|
||||||
|
- `i2s.DAC_CHANNEL_RIGHT`
|
||||||
|
- `i2s.DAC_CHANNEL_LEFT`
|
||||||
|
- `i2s.DAC_CHANNEL_BOTH`
|
||||||
|
- `adc1_channel` ADC1 channel number 0..7. Optional, defaults to off is omitted
|
||||||
|
- `cb` function called when transmit data is requested or received data is available
|
||||||
|
- the function is called with parameters `i2s_num` and `dir`
|
||||||
|
- `dir` is "tx" for TX data request. Function shall call `i2s.write()`.
|
||||||
|
- `dir` is "rx" for RX data available. Function shall call `i2s.read()`.
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
nil
|
`nil`
|
||||||
|
|
||||||
|
An error is thrown in case of invalid parameters or if the channel failed.
|
||||||
|
|
||||||
|
|
||||||
## i2s.stop()
|
## i2s.stop()
|
||||||
|
@ -61,37 +75,40 @@ Stop I2S bus
|
||||||
`i2s.stop(i2s_num)`
|
`i2s.stop(i2s_num)`
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
- `i2s_num` `1` or `2`
|
- `i2s_num` I2S peripheral 0 or 1
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
nil
|
`nil`
|
||||||
|
|
||||||
|
An error is thrown in case of invalid parameters or if the channel failed.
|
||||||
|
|
||||||
|
|
||||||
## i2s.read()
|
## i2s.read()
|
||||||
Read data from data-in
|
Read data from data-in
|
||||||
|
|
||||||
#### Syntax
|
#### Syntax
|
||||||
`i2s.read( i2s_num, size[, wait_ms] )`
|
`i2s.read(i2s_num, size[, wait_ms])`
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
- `adc_number` Only `adc.ADC1` now
|
- `i2s_num` I2S peripheral 0 or 1
|
||||||
- `size` Bytes to read
|
- `size` Bytes to read
|
||||||
- `wait_ms` Millisecond to wait if data is not ready. Default: `0` (not to wait)
|
- `wait_ms` Millisecond to wait if data is not ready. Optional, defaults to 0 (not to wait) if omitted.
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
Data read from data-in pin. If data is not ready in `wait_ms` millisecond, less than `size` bytes can be returned.
|
Data read from data-in pin. If data is not ready in `wait_ms` millisecond, less than `size` bytes can be returned.
|
||||||
|
|
||||||
|
|
||||||
## i2s.write()
|
## i2s.write()
|
||||||
Write to I2S bus
|
Write to I2S bus.
|
||||||
|
|
||||||
#### Syntax
|
#### Syntax
|
||||||
`i2s.write( i2s_num, size[, wait_ms] )`
|
`i2s.write(i2s_num, data)`
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
- `adc_number` Only `adc.ADC1` now
|
- `i2s_num` I2S peripheral 0 or 1
|
||||||
- `size` Bytes to send
|
- `data` string containing I2S stream data
|
||||||
- `wait_ms` Millisecond to wait if DMA buffer is full. Default: `0` (not to wait)
|
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
Integer, bytes wrote to buffer.
|
`nil`
|
||||||
|
|
||||||
|
An error is thrown in case of invalid parameters or if the channel failed.
|
||||||
|
|
Loading…
Reference in New Issue