fix qor mailboxes + all is in place for audio with thread, dma and irq

This commit is contained in:
Anthony Rabine 2023-07-25 22:06:12 +02:00
parent 51b202abfb
commit 3c652a3bde
11 changed files with 195 additions and 343 deletions

View file

@ -36,6 +36,7 @@
"numbers": "c", "numbers": "c",
"systick.h": "c", "systick.h": "c",
"critical_section.h": "c", "critical_section.h": "c",
"serializers.h": "c" "serializers.h": "c",
"cstring": "c"
} }
} }

View file

@ -1,4 +1,9 @@
// C library
#include <string.h>
#include <stdlib.h>
// OST common files // OST common files
#include "ost_hal.h" #include "ost_hal.h"
#include "debug.h" #include "debug.h"
@ -22,33 +27,10 @@
#include "audio_player.h" #include "audio_player.h"
#include "pico_i2s.h" #include "pico_i2s.h"
static volatile uint32_t msTicks = 0; // ===========================================================================================================
static audio_ctx_t audio_ctx; // CONSTANTS / DEFINES
// ===========================================================================================================
void __isr __time_critical_func(audio_i2s_dma_irq_handler)();
// ----------------------------------------------------------------------------
// SYSTEM HAL
// ----------------------------------------------------------------------------
#define UART_ID uart0
#define BAUD_RATE 115200
// We are using pins 0 and 1, but see the GPIO function select table in the
// datasheet for information on which other pins can be used.
#define UART_TX_PIN 0
#define UART_RX_PIN 1
static struct repeating_timer sys_timer;
// static audio_i2s_config_t i2s_config = {28, 26, 0};
static __attribute__((aligned(8))) pio_i2s i2s;
void ost_system_delay_ms(uint32_t delay)
{
busy_wait_ms(delay);
}
const uint8_t LED_PIN = 14; // GP 14 const uint8_t LED_PIN = 14; // GP 14
const uint8_t LCD_DC = 8; const uint8_t LCD_DC = 8;
@ -66,18 +48,36 @@ const uint8_t ROTARY_BUTTON = 3;
const uint8_t SD_CARD_CS = 17; const uint8_t SD_CARD_CS = 17;
const uint8_t SD_CARD_PRESENCE = 24; const uint8_t SD_CARD_PRESENCE = 24;
static bool sys_timer_callback(struct repeating_timer *t) #define UART_ID uart0
{ #define BAUD_RATE 115200
msTicks++;
// qor_switch_context(); // We are using pins 0 and 1, but see the GPIO function select table in the
// datasheet for information on which other pins can be used.
#define UART_TX_PIN 0
#define UART_RX_PIN 1
return true; // ===========================================================================================================
} // GLOBAL VARIABLES
// ===========================================================================================================
static __attribute__((aligned(8))) pio_i2s i2s;
static volatile uint32_t msTicks = 0;
static audio_ctx_t audio_ctx;
// ===========================================================================================================
// PROTOTYPES
// ===========================================================================================================
extern void init_spi(void); extern void init_spi(void);
void dma_init(); void dma_init();
void __isr __time_critical_func(audio_i2s_dma_irq_handler)();
// ===========================================================================================================
// OST HAL IMPLEMENTATION
// ===========================================================================================================
void ost_system_delay_ms(uint32_t delay)
{
busy_wait_ms(delay);
}
void gpio_callback(uint gpio, uint32_t events) void gpio_callback(uint gpio, uint32_t events)
{ {
@ -167,15 +167,10 @@ void ost_system_initialize()
.data_pin = 28, .data_pin = 28,
.clock_pin_base = 26}; .clock_pin_base = 26};
// i2s_program_start_synched(pio0, audio_i2s_dma_irq_handler, &i2s, &config); i2s_program_setup(pio0, audio_i2s_dma_irq_handler, &i2s, &config);
// pico_i2s_setup(&config);
audio_init(&audio_ctx); audio_init(&audio_ctx);
//------------------- System timer (1ms)
// add_repeating_timer_ms(1, sys_timer_callback, NULL, &sys_timer);
// ------------ Everything is initialized, print stuff here // ------------ Everything is initialized, print stuff here
debug_printf("System Clock: %lu\n", clock_get_hz(clk_sys)); debug_printf("System Clock: %lu\n", clock_get_hz(clk_sys));
} }
@ -304,21 +299,20 @@ void ost_display_transfer_multi(uint8_t *buff, uint32_t btr)
// AUDIO HAL // AUDIO HAL
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// extern shared_state_t shared_state;
// #include "pico/critical_section.h"
// critical_section_t acrit;
void ost_audio_play(const char *filename) void ost_audio_play(const char *filename)
{ {
audio_play(&audio_ctx, filename); audio_play(&audio_ctx, filename);
// audio_i2s_set_enabled(true); i2s.buffer_index = 0;
// audio_process(&audio_ctx);
// audio_step = 1; // On appelle une première fois le process pour récupérer et initialiser le premier buffer...
audio_process(&audio_ctx);
// Puis le deuxième ... (pour avoir un buffer d'avance)
audio_process(&audio_ctx);
// On lance les DMA
i2s_start(&i2s);
} }
int ost_audio_process() int ost_audio_process()
@ -326,39 +320,39 @@ int ost_audio_process()
return audio_process(&audio_ctx); return audio_process(&audio_ctx);
} }
static ost_audio_callback_t AudioCallBack = NULL;
void ost_audio_register_callback(ost_audio_callback_t cb) void ost_audio_register_callback(ost_audio_callback_t cb)
{ {
AudioCallBack = cb;
} }
void ost_hal_audio_frame_end() void ost_hal_audio_new_frame(const void *buff, int dma_trans_number)
{ {
if (dma_trans_number > STEREO_BUFFER_SIZE)
{
// Problème
return;
}
memcpy(i2s.out_ctrl_blocks[i2s.buffer_index], buff, dma_trans_number * sizeof(uint32_t));
i2s.buffer_index = 1 - i2s.buffer_index;
// uint dma_channel = shared_state.dma_channel; //
// if (dma_irqn_get_channel_status(PICO_AUDIO_I2S_DMA_IRQ, dma_channel))
// {
// dma_irqn_acknowledge_channel(PICO_AUDIO_I2S_DMA_IRQ, dma_channel);
// }
}
void ost_hal_audio_frame_start(const volatile void *buff, int dma_trans_number)
{
// dma_channel_transfer_from_buffer_now(shared_state.dma_channel, buff, dma_trans_number); // dma_channel_transfer_from_buffer_now(shared_state.dma_channel, buff, dma_trans_number);
// dma_channel_start(shared_state.dma_channel); // dma_channel_start(shared_state.dma_channel);
dma_hw->ints0 = 1u << i2s.dma_ch_out_data; // clear the IRQ // dma_hw->ints0 = 1u << i2s.dma_ch_out_data; // clear the IRQ
} }
void __isr __time_critical_func(audio_i2s_dma_irq_handler)() void __isr __time_critical_func(audio_i2s_dma_irq_handler)()
{ {
/* dma_hw->ints0 = 1u << i2s.dma_ch_out_data; // clear the IRQ
uint dma_channel = shared_state.dma_channel;
if (dma_irqn_get_channel_status(PICO_AUDIO_I2S_DMA_IRQ, dma_channel))
{
dma_irqn_acknowledge_channel(PICO_AUDIO_I2S_DMA_IRQ, dma_channel);
}
audio_process(&audio_ctx); // Warn the application layer that we have done on that channel
*/ if (AudioCallBack != NULL)
{
AudioCallBack();
}
} }
#if 0 // legacy audio test #if 0 // legacy audio test

View file

@ -16,10 +16,10 @@
#include "debug.h" #include "debug.h"
void pico_i2s_set_frequency(const audio_i2s_config_t *config) void pico_i2s_set_frequency(const pio_i2s *i2s, const audio_i2s_config_t *config)
{ {
float bitClk = config->freq * config->bps * 2.0 /* channels */ * 2.0 /* edges per clock */; float bitClk = config->freq * config->bps * 2.0 /* channels */ * 2.0 /* edges per clock */;
// pio_sm_set_clkdiv(audio_pio, shared_state.pio_sm, (float)clock_get_hz(clk_sys) / bitClk); pio_sm_set_clkdiv(i2s->pio, i2s->sm_dout, (float)clock_get_hz(clk_sys) / bitClk);
} }
#if 0 #if 0
@ -64,7 +64,7 @@ void audio_i2s_set_enabled(bool enabled)
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
static void dma_double_buffer_init(pio_i2s *i2s, void (*dma_handler)(void)) static void dma_double_buffer_init(pio_i2s *i2s)
{ {
i2s->dma_ch_out_ctrl = dma_claim_unused_channel(true); i2s->dma_ch_out_ctrl = dma_claim_unused_channel(true);
i2s->dma_ch_out_data = dma_claim_unused_channel(true); i2s->dma_ch_out_data = dma_claim_unused_channel(true);
@ -75,14 +75,25 @@ static void dma_double_buffer_init(pio_i2s *i2s, void (*dma_handler)(void))
dma_channel_config c = dma_channel_get_default_config(i2s->dma_ch_out_ctrl); dma_channel_config c = dma_channel_get_default_config(i2s->dma_ch_out_ctrl);
channel_config_set_read_increment(&c, true); channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false); channel_config_set_write_increment(&c, false);
// i2s->out_ctrl_blocks pointe sur deux emplacements, 4 octets par emplacement (qui est une adresse)
// A chaque fois que le DMA de contrôle sera activé, l'adresse va s'incrémenter de 4 octets (DMA_SIZE_32)
// Dès lors :
// - On commence à l'index 0
// - Puis l'index 1
// On va revenir à l'index 0 tous les ... 8 octets, donc on programme ce décalage (3 bits)
channel_config_set_ring(&c, false, 3); channel_config_set_ring(&c, false, 3);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32); channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
dma_channel_configure(i2s->dma_ch_out_ctrl, &c, &dma_hw->ch[i2s->dma_ch_out_data].al3_read_addr_trig, i2s->out_ctrl_blocks, 1, false); dma_channel_configure(i2s->dma_ch_out_ctrl, &c, &dma_hw->ch[i2s->dma_ch_out_data].al3_read_addr_trig, i2s->out_ctrl_blocks, 1, false);
// la destination est l'alias al3_read_addr_trig qui va donc modifier l'adresse de début du transfer DMA et enclencher le démarrage
// Nous avons deux actions, c'est pour cela que c'est un alias
c = dma_channel_get_default_config(i2s->dma_ch_out_data); c = dma_channel_get_default_config(i2s->dma_ch_out_data);
channel_config_set_read_increment(&c, true); channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false); channel_config_set_write_increment(&c, false);
channel_config_set_chain_to(&c, i2s->dma_ch_out_ctrl); channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_chain_to(&c, i2s->dma_ch_out_ctrl); // On va chaîner ce DMA au contrôle: lorsque le DMA est terminé, le DMA de contrôle va s'activer... et ainsi de suite
channel_config_set_dreq(&c, pio_get_dreq(i2s->pio, i2s->sm_dout, true)); channel_config_set_dreq(&c, pio_get_dreq(i2s->pio, i2s->sm_dout, true));
dma_channel_configure(i2s->dma_ch_out_data, dma_channel_configure(i2s->dma_ch_out_data,
@ -91,15 +102,9 @@ static void dma_double_buffer_init(pio_i2s *i2s, void (*dma_handler)(void))
NULL, NULL,
STEREO_BUFFER_SIZE, STEREO_BUFFER_SIZE,
false); false);
dma_channel_set_irq0_enabled(i2s->dma_ch_out_data, true);
irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
irq_set_enabled(DMA_IRQ_0, true);
dma_channel_start(i2s->dma_ch_out_ctrl);
} }
static void i2s_sync_program_init(PIO pio, pio_i2s *i2s, audio_i2s_config_t *config) static void i2s_sync_program_init(PIO pio, pio_i2s *i2s, const audio_i2s_config_t *config)
{ {
uint offset = 0; uint offset = 0;
i2s->pio = pio; i2s->pio = pio;
@ -110,13 +115,46 @@ static void i2s_sync_program_init(PIO pio, pio_i2s *i2s, audio_i2s_config_t *con
offset = pio_add_program(pio0, &i2s_out_master_program); offset = pio_add_program(pio0, &i2s_out_master_program);
// 4th argument is bit depth, 5th dout, 6th bclk pin base (lrclk is bclk pin + 1) // 4th argument is bit depth, 5th dout, 6th bclk pin base (lrclk is bclk pin + 1)
i2s_out_master_program_init(pio, i2s->sm_dout, offset, config->bps, config->data_pin, config->clock_pin_base); i2s_out_master_program_init(pio, i2s->sm_dout, offset, config->bps, config->data_pin, config->clock_pin_base);
// pio_sm_set_clkdiv(pio, i2s->sm_dout, 89); // Approximately 11KHz audio
} }
void i2s_program_start_synched(PIO pio, void (*dma_handler)(void), pio_i2s *i2s, audio_i2s_config_t *config) void i2s_program_setup(PIO pio, void (*dma_handler)(void), pio_i2s *i2s, const audio_i2s_config_t *config)
{ {
// i2s_sync_program_init(pio, i2s); if (((uint32_t)i2s & 0x7) != 0)
pico_i2s_set_frequency(config); {
dma_double_buffer_init(i2s, dma_handler); debug_printf("pio_i2s argument must be 8-byte aligned!\r\n");
}
i2s_sync_program_init(pio, i2s, config);
pico_i2s_set_frequency(i2s, config); // call after PIO configuration
dma_double_buffer_init(i2s);
irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
pio_enable_sm_mask_in_sync(i2s->pio, i2s->sm_mask); pio_enable_sm_mask_in_sync(i2s->pio, i2s->sm_mask);
} }
void i2s_start(pio_i2s *i2s)
{
// D'abord on va paramétrer les diverses interruptions
dma_channel_set_irq0_enabled(i2s->dma_ch_out_data, true);
irq_set_enabled(DMA_IRQ_0, true);
// YAAAAAAA on lance!
dma_channel_start(i2s->dma_ch_out_ctrl);
}
static void pico_gracefully_stop_dma(uint channel)
{
// See errata sheet to avoid spurious interrupts
// disable the channel on IRQ0
dma_channel_set_irq0_enabled(channel, false);
// abort the channel
dma_channel_abort(channel);
// clear the spurious IRQ (if there was one)
dma_channel_acknowledge_irq0(channel);
}
void i2s_stop(pio_i2s *i2s)
{
pico_gracefully_stop_dma(i2s->dma_ch_out_ctrl);
pico_gracefully_stop_dma(i2s->dma_ch_out_data);
irq_set_enabled(DMA_IRQ_0, false);
}

View file

@ -13,158 +13,15 @@
#include "hardware/irq.h" #include "hardware/irq.h"
#include "hardware/pio.h" #include "hardware/pio.h"
#include "audio_player.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
#endif #endif
#if 0 #define AUDIO_BUFFER_FRAMES SIZE_OF_SAMPLES
#define STEREO_BUFFER_SIZE AUDIO_BUFFER_FRAMES * 2 // for left + right
/** \file audio_i2s.h
* \defgroup pico_audio_i2s pico_audio_i2s
* I2S audio output using the PIO
*
* This library uses the \ref hardware_pio system to implement a I2S audio interface
*
* \todo Must be more we need to say here.
* \todo certainly need an example
*
*/
#ifndef PICO_AUDIO_I2S_DMA_IRQ
#ifdef PICO_AUDIO_DMA_IRQ
#define PICO_AUDIO_I2S_DMA_IRQ PICO_AUDIO_DMA_IRQ
#else
#define PICO_AUDIO_I2S_DMA_IRQ 0
#endif
#endif
#ifndef PICO_AUDIO_I2S_PIO
#ifdef PICO_AUDIO_PIO
#define PICO_AUDIO_I2S_PIO PICO_AUDIO_PIO
#else
#define PICO_AUDIO_I2S_PIO 0
#endif
#endif
#if !(PICO_AUDIO_I2S_DMA_IRQ == 0 || PICO_AUDIO_I2S_DMA_IRQ == 1)
#error PICO_AUDIO_I2S_DMA_IRQ must be 0 or 1
#endif
#if !(PICO_AUDIO_I2S_PIO == 0 || PICO_AUDIO_I2S_PIO == 1)
#error PICO_AUDIO_I2S_PIO ust be 0 or 1
#endif
#ifndef PICO_AUDIO_I2S_MAX_CHANNELS
#ifdef PICO_AUDIO_MAX_CHANNELS
#define PICO_AUDIO_I2S_MAX_CHANNELS PICO_AUDIO_MAX_CHANNELS
#else
#define PICO_AUDIO_I2S_MAX_CHANNELS 2u
#endif
#endif
#ifndef PICO_AUDIO_I2S_BUFFERS_PER_CHANNEL
#ifdef PICO_AUDIO_BUFFERS_PER_CHANNEL
#define PICO_AUDIO_I2S_BUFFERS_PER_CHANNEL PICO_AUDIO_BUFFERS_PER_CHANNEL
#else
#define PICO_AUDIO_I2S_BUFFERS_PER_CHANNEL 3u
#endif
#endif
#ifndef PICO_AUDIO_I2S_BUFFER_SAMPLE_LENGTH
#ifdef PICO_AUDIO_BUFFER_SAMPLE_LENGTH
#define PICO_AUDIO_I2S_BUFFER_SAMPLE_LENGTH PICO_AUDIO_BUFFER_SAMPLE_LENGTH
#else
#define PICO_AUDIO_I2S_BUFFER_SAMPLE_LENGTH 576u
#endif
#endif
#ifndef PICO_AUDIO_I2S_SILENCE_BUFFER_SAMPLE_LENGTH
#ifdef PICO_AUDIO_I2S_SILENCE_BUFFER_SAMPLE_LENGTH
#define PICO_AUDIO_I2S_SILENCE_BUFFER_SAMPLE_LENGTH PICO_AUDIO_SILENCE_BUFFER_SAMPLE_LENGTH
#else
#define PICO_AUDIO_I2S_SILENCE_BUFFER_SAMPLE_LENGTH 256u
#endif
#endif
// Allow use of pico_audio driver without actually doing anything much
#ifndef PICO_AUDIO_I2S_NOOP
#ifdef PICO_AUDIO_NOOP
#define PICO_AUDIO_I2S_NOOP PICO_AUDIO_NOOP
#else
#define PICO_AUDIO_I2S_NOOP 0
#endif
#endif
#ifndef PICO_AUDIO_I2S_MONO_INPUT
#define PICO_AUDIO_I2S_MONO_INPUT 0
#endif
#ifndef PICO_AUDIO_I2S_MONO_OUTPUT
#define PICO_AUDIO_I2S_MONO_OUTPUT 0
#endif
#ifndef PICO_AUDIO_I2S_DATA_PIN
// #warning PICO_AUDIO_I2S_DATA_PIN should be defined when using AUDIO_I2S
#define PICO_AUDIO_I2S_DATA_PIN 28
#endif
#ifndef PICO_AUDIO_I2S_CLOCK_PIN_BASE
// #warning PICO_AUDIO_I2S_CLOCK_PIN_BASE should be defined when using AUDIO_I2S
#define PICO_AUDIO_I2S_CLOCK_PIN_BASE 26
#endif
/** \brief Base configuration structure used when setting up
* \ingroup pico_audio_i2s
*/
typedef struct
{
uint32_t freq;
uint32_t bps;
uint8_t data_pin;
uint8_t clock_pin_base;
} audio_i2s_config_t;
typedef struct
{
uint32_t freq;
uint8_t pio_sm;
uint8_t dma_channel;
} shared_state_t;
typedef struct audio_format
{
uint32_t sample_freq; ///< Sample frequency in Hz
uint16_t format; ///< Audio format \ref audio_formats
uint16_t channel_count; ///< Number of channels
} audio_format_t;
/** \brief Set up system to output I2S audio
* \ingroup pico_audio_i2s
*
* \param intended_audio_format \todo
* \param config The configuration to apply.
*/
void pico_i2s_setup(const audio_i2s_config_t *config);
/** \brief Set up system to output I2S audio
* \ingroup pico_audio_i2s
*
* \param enable true to enable I2S audio, false to disable.
*/
void audio_i2s_set_enabled(bool enabled);
void audio_start_dma_transfer(const int32_t *bytes, uint32_t count);
#endif
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
#define AUDIO_BUFFER_FRAMES 48
#define STEREO_BUFFER_SIZE AUDIO_BUFFER_FRAMES * 2
typedef struct typedef struct
{ {
@ -177,16 +34,22 @@ extern "C"
typedef struct pio_i2s typedef struct pio_i2s
{ {
int32_t output_buffer[STEREO_BUFFER_SIZE * 2]; // double buffering, so x2
int32_t *out_ctrl_blocks[2];
PIO pio; PIO pio;
uint8_t sm_mask; uint8_t sm_mask;
uint8_t sm_dout; uint8_t sm_dout;
uint dma_ch_out_ctrl; uint dma_ch_out_ctrl;
uint dma_ch_out_data; uint dma_ch_out_data;
int32_t *out_ctrl_blocks[2]; int buffer_index;
int32_t output_buffer[STEREO_BUFFER_SIZE * 2];
} pio_i2s; } pio_i2s;
void i2s_program_start_synched(PIO pio, void (*dma_handler)(void), pio_i2s *i2s, audio_i2s_config_t *config); void i2s_program_setup(PIO pio, void (*dma_handler)(void), pio_i2s *i2s, const audio_i2s_config_t *config);
void i2s_start(pio_i2s *i2s);
void i2s_stop(pio_i2s *i2s);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -10,10 +10,8 @@
#include "ost_hal.h" #include "ost_hal.h"
#include "serializers.h" #include "serializers.h"
#define SIZE_OF_SAMPLES (128) // in bytes
// Audio Double Buffer for DMA transfer // Audio Double Buffer for DMA transfer
int32_t audio_buf[2][SIZE_OF_SAMPLES]; int32_t audio_buf[SIZE_OF_SAMPLES];
// int16_t audio_buf16[2][SIZE_OF_SAMPLES]; // int16_t audio_buf16[2][SIZE_OF_SAMPLES];
// Audio Buffer for File Read // Audio Buffer for File Read
@ -64,14 +62,10 @@ void audio_init(audio_ctx_t *ctx)
for (int i = 0; i < SIZE_OF_SAMPLES; i++) for (int i = 0; i < SIZE_OF_SAMPLES; i++)
{ {
audio_buf[0][i] = DAC_ZERO_VALUE; audio_buf[i] = DAC_ZERO_VALUE;
audio_buf[1][i] = DAC_ZERO_VALUE;
// audio_buf16[0][i] = DAC_ZERO_VALUE;
// audio_buf16[1][i] = DAC_ZERO_VALUE;
} }
ctx->dma_trans_number = SIZE_OF_SAMPLES / 4; ctx->transfer_size = SIZE_OF_SAMPLES / 4;
} }
static int list_chunk_is_info_type(audio_ctx_t *ctx) static int list_chunk_is_info_type(audio_ctx_t *ctx)
@ -188,7 +182,7 @@ static int get_audio_buf(audio_ctx_t *ctx, int32_t *buf_32b)
{ {
debug_printf("ERROR: f_read %d, data_offset = %d\n\r", (int)fr, (int)ctx->audio_info.data_offset); debug_printf("ERROR: f_read %d, data_offset = %d\n\r", (int)fr, (int)ctx->audio_info.data_offset);
f_close(&ctx->fil); f_close(&ctx->fil);
ctx->dma_trans_number = number / 4; ctx->transfer_size = number / 4;
return 1; return 1;
} }
if (ctx->audio_info.data_size <= ctx->audio_info.data_offset) if (ctx->audio_info.data_size <= ctx->audio_info.data_offset)
@ -232,40 +226,31 @@ static int get_audio_buf(audio_ctx_t *ctx, int32_t *buf_32b)
*/ */
// ctx->audio_info.lvl_l = get_level(lvl_l / (number / 4)); // ctx->audio_info.lvl_l = get_level(lvl_l / (number / 4));
// ctx->audio_info.lvl_r = get_level(lvl_r / (number / 4)); // ctx->audio_info.lvl_r = get_level(lvl_r / (number / 4));
ctx->dma_trans_number = (number / 4); // 32 bytes tranfers ctx->transfer_size = (number / 4); // 32 bytes tranfers
return _next_is_end; return _next_is_end;
} }
int audio_process(audio_ctx_t *ctx) int audio_process(audio_ctx_t *ctx)
{ {
int nxt1 = (ctx->count & 0x1) ^ 0x1;
int nxt2 = 1 - nxt1;
// dma_flag_clear(DMA1, DMA_CH1, DMA_FLAG_FTF);
// dma_channel_disable(DMA1, DMA_CH1);
ost_hal_audio_frame_end();
if (ctx->next_is_end) if (ctx->next_is_end)
{ {
ctx->playing = 0; ctx->playing = 0;
ctx->pausing = 0; ctx->pausing = 0;
} }
// init_dma_i2s2(audio_buf[nxt1], dma_trans_number);
// dma_channel_enable(DMA1, DMA_CH1);
ost_hal_audio_frame_start(audio_buf[nxt1], ctx->dma_trans_number);
if (ctx->playing && !ctx->pausing) if (ctx->playing && !ctx->pausing)
{ {
ctx->next_is_end = get_audio_buf(ctx, audio_buf[nxt2]); // Récupération du buffer audio à partir du disque
ctx->next_is_end = get_audio_buf(ctx, &audio_buf[0]);
ost_hal_audio_new_frame(&audio_buf[0], ctx->transfer_size);
} }
else else
{ {
for (int i = 0; i < SIZE_OF_SAMPLES; i++) for (int i = 0; i < SIZE_OF_SAMPLES; i++)
{ {
audio_buf[nxt2][i] = DAC_ZERO_VALUE; audio_buf[i] = DAC_ZERO_VALUE;
} }
ctx->dma_trans_number = SIZE_OF_SAMPLES / 4; ctx->transfer_size = SIZE_OF_SAMPLES / 4;
} }
ctx->count++; ctx->count++;

View file

@ -6,6 +6,7 @@
#include <ff.h> #include <ff.h>
#define SIZE_OF_SAMPLES (128) // in bytes
#define FILENAME_MAX_SIZE 260 #define FILENAME_MAX_SIZE 260
typedef struct typedef struct
@ -29,7 +30,7 @@ typedef struct
{ {
FIL fil; FIL fil;
audio_info_type_t audio_info; audio_info_type_t audio_info;
int32_t dma_trans_number; int32_t transfer_size;
uint16_t idx_play; uint16_t idx_play;
int next_is_end; int next_is_end;
int playing; int playing;

View file

@ -120,30 +120,6 @@ void UserTask_1(void *args)
} }
} }
void UserTask_2(void *args)
{
static ost_event_t wake_up;
wake_up.ev = 34;
while (1)
{
for (int i = 0; i < 65500; i++)
{
for (int j = 0; j < 300; j++)
;
}
debug_printf("X\n");
for (int i = 0; i < 65500; i++)
{
for (int j = 0; j < 100; j++)
;
}
qor_mbox_notify(&b, (void **)&wake_up, 1);
}
}
// =========================================================================================================== // ===========================================================================================================
// SD CARD TASK // SD CARD TASK
// =========================================================================================================== // ===========================================================================================================
@ -152,6 +128,8 @@ static uint32_t AudioStack[4096];
static qor_mbox_t AudioMailBox; static qor_mbox_t AudioMailBox;
static ost_event_t wake_up;
typedef struct typedef struct
{ {
uint8_t ev; uint8_t ev;
@ -162,6 +140,8 @@ ost_audio_event_t audio_queue[10];
// End of DMA transfer callback // End of DMA transfer callback
static void audio_callback(void) static void audio_callback(void)
{ {
qor_mbox_notify(&b, (void **)&wake_up, QOR_MBOX_OPTION_SEND_BACK);
gpio_xor_mask(1 << 1);
} }
void AudioTask(void *args) void AudioTask(void *args)
@ -169,6 +149,8 @@ void AudioTask(void *args)
picture_show("example.bmp"); picture_show("example.bmp");
// ost_audio_play("out2.wav"); // ost_audio_play("out2.wav");
wake_up.ev = 34;
qor_mbox_init(&AudioMailBox, (void **)&audio_queue, 10); qor_mbox_init(&AudioMailBox, (void **)&audio_queue, 10);
ost_audio_register_callback(audio_callback); ost_audio_register_callback(audio_callback);
@ -182,37 +164,54 @@ void AudioTask(void *args)
while (1) while (1)
{ {
// Benchmark code
#if 0
if (onetime) if (onetime)
{ {
onetime = false; onetime = false;
gpio_put(1, 1);
ost_audio_play("out2.wav"); ost_audio_play("out2.wav");
gpio_put(1, 0);
int isPlaying = 0; int isPlaying = 0;
int count = 0; int count = 0;
do do
{ {
gpio_put(1, 1);
isPlaying = ost_audio_process(); isPlaying = ost_audio_process();
gpio_put(1, 0);
count++; count++;
} while (isPlaying); } while (isPlaying);
debug_printf("Packets: %d\r\n", count); debug_printf("Packets: %d\r\n", count);
} }
#endif
// ost_event_t *e = NULL; ost_audio_play("out2.wav");
// uint32_t res = qor_mbox_wait(&b, (void **)&e, 30);
// if (res == QOR_MBOX_OK) ost_event_t *e = NULL;
// {
// }
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 0); int isPlaying = 0;
qor_sleep(500); int count = 0;
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 1); do
qor_sleep(500); {
uint32_t res = qor_mbox_wait(&AudioMailBox, (void **)&e, 30); // On devrait recevoir un message toutes les 3ms (durée d'envoi d'un buffer I2S)
if (res == QOR_MBOX_OK)
{
isPlaying = ost_audio_process();
}
count++;
} while (isPlaying);
for (;;)
{
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 0);
qor_sleep(500);
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 1);
qor_sleep(500);
}
} }
} }

View file

@ -107,8 +107,7 @@ extern "C"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// AUDIO HAL // AUDIO HAL
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void ost_hal_audio_frame_end(); void ost_hal_audio_new_frame(const void *buffer, int size);
void ost_hal_audio_frame_start(const volatile void *, int dma_trans_number);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -221,7 +221,6 @@ void qor_create_thread(qor_tcb_t *tcb, thread_func_t task, uint32_t *stack, uint
tcb->state = qor_tcb_state_active; tcb->state = qor_tcb_state_active;
tcb->wait_time = 0; tcb->wait_time = 0;
tcb->state = qor_tcb_state_active;
tcb->priority = priority; tcb->priority = priority;
tcb->name = name; tcb->name = name;
tcb->next = NULL; tcb->next = NULL;
@ -341,7 +340,10 @@ void qor_scheduler(void)
} }
else if (best_sleeping != NULL) else if (best_sleeping != NULL)
{ {
// On va réveiller un endormi, car son temps d'attente est dépassé (ok ou timeout, ça dépend si c'est un sleep volontaire ou attente de mailbox dépassée)
RunPt = best_sleeping; RunPt = best_sleeping;
RunPt->state = qor_tcb_state_active; // devient actif
RunPt->ts = 0; // means timeout
} }
else else
{ {
@ -382,6 +384,7 @@ void qor_mbox_init(qor_mbox_t *mbox, void **msgBuffer, uint32_t maxCount)
mbox->read = 0; mbox->read = 0;
mbox->read = 0; mbox->read = 0;
mbox->head = NULL; mbox->head = NULL;
mbox->count = 0;
} }
uint32_t qor_mbox_wait(qor_mbox_t *mbox, void **msg, uint32_t wait_ms) uint32_t qor_mbox_wait(qor_mbox_t *mbox, void **msg, uint32_t wait_ms)
@ -396,6 +399,13 @@ uint32_t qor_mbox_wait(qor_mbox_t *mbox, void **msg, uint32_t wait_ms)
RunPt->mbox = mbox; RunPt->mbox = mbox;
mbox->head = RunPt; mbox->head = RunPt;
qor_sleep(wait_ms); qor_sleep(wait_ms);
disable_irq();
if (RunPt->ts == 0)
{
enable_irq();
return QOR_MBOX_TIMEOUT;
}
} }
else else
{ {
@ -445,11 +455,12 @@ uint32_t qor_mbox_notify(qor_mbox_t *mbox, void *msg, uint32_t notifyOption)
} }
mbox->count++; mbox->count++;
// We warn all waiting threads that a new message is available // We warn waiting thread that a new message is available
qor_tcb_t *t = mbox->head; qor_tcb_t *t = mbox->head;
if (t != NULL) if (t != NULL)
{ {
t->wait_time = 0; t->wait_time = 0;
t->state = qor_tcb_state_active; // force wake up
} }
enable_irq(); enable_irq();

View file

@ -84,8 +84,9 @@ typedef struct
} mbox_stats_t; } mbox_stats_t;
#define QOR_MBOX_OK 1 #define QOR_MBOX_OK 1
#define QOR_MBOX_ERROR 2 #define QOR_MBOX_TIMEOUT 2
#define QOR_MBOX_FULL 3 #define QOR_MBOX_ERROR 3
#define QOR_MBOX_FULL 4
void qor_mbox_init(qor_mbox_t *mbox, void **msgBuffer, uint32_t maxCount); void qor_mbox_init(qor_mbox_t *mbox, void **msgBuffer, uint32_t maxCount);
uint32_t qor_mbox_wait(qor_mbox_t *mbox, void **msg, uint32_t wait_ms); uint32_t qor_mbox_wait(qor_mbox_t *mbox, void **msg, uint32_t wait_ms);

View file

@ -20,46 +20,6 @@
@ The Cortex-M0 is limited on the thumb number of instructionss @ The Cortex-M0 is limited on the thumb number of instructionss
@ the context restore is therefore a bit more complex that M3 or M4 CPU @ the context restore is therefore a bit more complex that M3 or M4 CPU
@ One limitation is the POP instruction that cannot access to the HI registers (registers after R7) @ One limitation is the POP instruction that cannot access to the HI registers (registers after R7)
@
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@ | |
@ -------------
@
@
@
@
qor_go: qor_go: