diff --git a/software/.vscode/settings.json b/software/.vscode/settings.json index 6fa0935..bff4832 100644 --- a/software/.vscode/settings.json +++ b/software/.vscode/settings.json @@ -36,6 +36,7 @@ "numbers": "c", "systick.h": "c", "critical_section.h": "c", - "serializers.h": "c" + "serializers.h": "c", + "cstring": "c" } } \ No newline at end of file diff --git a/software/platform/raspberry-pico-w/pico_hal_wrapper.c b/software/platform/raspberry-pico-w/pico_hal_wrapper.c index 7c4317c..78ab591 100644 --- a/software/platform/raspberry-pico-w/pico_hal_wrapper.c +++ b/software/platform/raspberry-pico-w/pico_hal_wrapper.c @@ -1,4 +1,9 @@ + +// C library +#include +#include + // OST common files #include "ost_hal.h" #include "debug.h" @@ -22,33 +27,10 @@ #include "audio_player.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 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_PRESENCE = 24; -static bool sys_timer_callback(struct repeating_timer *t) -{ - msTicks++; +#define UART_ID uart0 +#define BAUD_RATE 115200 - // 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); - 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) { @@ -167,15 +167,10 @@ void ost_system_initialize() .data_pin = 28, .clock_pin_base = 26}; - // i2s_program_start_synched(pio0, audio_i2s_dma_irq_handler, &i2s, &config); - - // pico_i2s_setup(&config); + i2s_program_setup(pio0, audio_i2s_dma_irq_handler, &i2s, &config); audio_init(&audio_ctx); - //------------------- System timer (1ms) - // add_repeating_timer_ms(1, sys_timer_callback, NULL, &sys_timer); - // ------------ Everything is initialized, print stuff here 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 // ---------------------------------------------------------------------------- -// extern shared_state_t shared_state; - -// #include "pico/critical_section.h" - -// critical_section_t acrit; - void ost_audio_play(const char *filename) { - audio_play(&audio_ctx, filename); - // audio_i2s_set_enabled(true); - // audio_process(&audio_ctx); + i2s.buffer_index = 0; - // 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() @@ -326,39 +320,39 @@ int ost_audio_process() return audio_process(&audio_ctx); } +static ost_audio_callback_t AudioCallBack = NULL; + 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_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)() { - /* - 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); - } + dma_hw->ints0 = 1u << i2s.dma_ch_out_data; // clear the IRQ - audio_process(&audio_ctx); - */ + // Warn the application layer that we have done on that channel + if (AudioCallBack != NULL) + { + AudioCallBack(); + } } #if 0 // legacy audio test diff --git a/software/platform/raspberry-pico-w/pico_i2s.c b/software/platform/raspberry-pico-w/pico_i2s.c index 8a75014..c44a0b7 100644 --- a/software/platform/raspberry-pico-w/pico_i2s.c +++ b/software/platform/raspberry-pico-w/pico_i2s.c @@ -16,10 +16,10 @@ #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 */; - // 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 @@ -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_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); channel_config_set_read_increment(&c, true); 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_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); + // 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); channel_config_set_read_increment(&c, true); 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)); 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, STEREO_BUFFER_SIZE, 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; 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); // 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); - // 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); - pico_i2s_set_frequency(config); - dma_double_buffer_init(i2s, dma_handler); + if (((uint32_t)i2s & 0x7) != 0) + { + 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); } + +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); +} diff --git a/software/platform/raspberry-pico-w/pico_i2s.h b/software/platform/raspberry-pico-w/pico_i2s.h index 033b9c5..257bdb0 100644 --- a/software/platform/raspberry-pico-w/pico_i2s.h +++ b/software/platform/raspberry-pico-w/pico_i2s.h @@ -13,158 +13,15 @@ #include "hardware/irq.h" #include "hardware/pio.h" +#include "audio_player.h" + #ifdef __cplusplus extern "C" { #endif -#if 0 - -/** \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 +#define AUDIO_BUFFER_FRAMES SIZE_OF_SAMPLES +#define STEREO_BUFFER_SIZE AUDIO_BUFFER_FRAMES * 2 // for left + right typedef struct { @@ -177,16 +34,22 @@ extern "C" typedef struct pio_i2s { + int32_t output_buffer[STEREO_BUFFER_SIZE * 2]; // double buffering, so x2 + int32_t *out_ctrl_blocks[2]; + PIO pio; uint8_t sm_mask; uint8_t sm_dout; uint dma_ch_out_ctrl; uint dma_ch_out_data; - int32_t *out_ctrl_blocks[2]; - int32_t output_buffer[STEREO_BUFFER_SIZE * 2]; + int buffer_index; + } 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 } diff --git a/software/system/audio_player.c b/software/system/audio_player.c index 762c165..b9efeab 100644 --- a/software/system/audio_player.c +++ b/software/system/audio_player.c @@ -10,10 +10,8 @@ #include "ost_hal.h" #include "serializers.h" -#define SIZE_OF_SAMPLES (128) // in bytes - // 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]; // 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++) { - audio_buf[0][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; + audio_buf[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) @@ -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); f_close(&ctx->fil); - ctx->dma_trans_number = number / 4; + ctx->transfer_size = number / 4; return 1; } 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_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; } 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) { ctx->playing = 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) { - 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 { 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++; diff --git a/software/system/audio_player.h b/software/system/audio_player.h index 3c68352..9699441 100644 --- a/software/system/audio_player.h +++ b/software/system/audio_player.h @@ -6,6 +6,7 @@ #include +#define SIZE_OF_SAMPLES (128) // in bytes #define FILENAME_MAX_SIZE 260 typedef struct @@ -29,7 +30,7 @@ typedef struct { FIL fil; audio_info_type_t audio_info; - int32_t dma_trans_number; + int32_t transfer_size; uint16_t idx_play; int next_is_end; int playing; diff --git a/software/system/main.c b/software/system/main.c index e2b13a7..f8314d2 100644 --- a/software/system/main.c +++ b/software/system/main.c @@ -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 // =========================================================================================================== @@ -152,6 +128,8 @@ static uint32_t AudioStack[4096]; static qor_mbox_t AudioMailBox; +static ost_event_t wake_up; + typedef struct { uint8_t ev; @@ -162,6 +140,8 @@ ost_audio_event_t audio_queue[10]; // End of DMA transfer callback 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) @@ -169,6 +149,8 @@ void AudioTask(void *args) picture_show("example.bmp"); // ost_audio_play("out2.wav"); + wake_up.ev = 34; + qor_mbox_init(&AudioMailBox, (void **)&audio_queue, 10); ost_audio_register_callback(audio_callback); @@ -182,37 +164,54 @@ void AudioTask(void *args) while (1) { +// Benchmark code +#if 0 if (onetime) { onetime = false; - gpio_put(1, 1); ost_audio_play("out2.wav"); - gpio_put(1, 0); int isPlaying = 0; int count = 0; do { - + gpio_put(1, 1); isPlaying = ost_audio_process(); + gpio_put(1, 0); count++; } while (isPlaying); debug_printf("Packets: %d\r\n", count); } +#endif - // ost_event_t *e = NULL; - // uint32_t res = qor_mbox_wait(&b, (void **)&e, 30); + ost_audio_play("out2.wav"); - // if (res == QOR_MBOX_OK) - // { - // } + ost_event_t *e = NULL; - ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 0); - qor_sleep(500); - ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 1); - qor_sleep(500); + int isPlaying = 0; + int count = 0; + do + { + 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); + } } } diff --git a/software/system/ost_hal.h b/software/system/ost_hal.h index cb244fb..a46d596 100644 --- a/software/system/ost_hal.h +++ b/software/system/ost_hal.h @@ -107,8 +107,7 @@ extern "C" // ---------------------------------------------------------------------------- // AUDIO HAL // ---------------------------------------------------------------------------- - void ost_hal_audio_frame_end(); - void ost_hal_audio_frame_start(const volatile void *, int dma_trans_number); + void ost_hal_audio_new_frame(const void *buffer, int size); #ifdef __cplusplus } diff --git a/software/system/qor.c b/software/system/qor.c index 7e71227..580dd35 100644 --- a/software/system/qor.c +++ b/software/system/qor.c @@ -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->wait_time = 0; - tcb->state = qor_tcb_state_active; tcb->priority = priority; tcb->name = name; tcb->next = NULL; @@ -341,7 +340,10 @@ void qor_scheduler(void) } 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->state = qor_tcb_state_active; // devient actif + RunPt->ts = 0; // means timeout } 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->head = NULL; + mbox->count = 0; } 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; mbox->head = RunPt; qor_sleep(wait_ms); + + disable_irq(); + if (RunPt->ts == 0) + { + enable_irq(); + return QOR_MBOX_TIMEOUT; + } } else { @@ -445,11 +455,12 @@ uint32_t qor_mbox_notify(qor_mbox_t *mbox, void *msg, uint32_t notifyOption) } 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; if (t != NULL) { t->wait_time = 0; + t->state = qor_tcb_state_active; // force wake up } enable_irq(); diff --git a/software/system/qor.h b/software/system/qor.h index e622505..5196371 100644 --- a/software/system/qor.h +++ b/software/system/qor.h @@ -84,8 +84,9 @@ typedef struct } mbox_stats_t; #define QOR_MBOX_OK 1 -#define QOR_MBOX_ERROR 2 -#define QOR_MBOX_FULL 3 +#define QOR_MBOX_TIMEOUT 2 +#define QOR_MBOX_ERROR 3 +#define QOR_MBOX_FULL 4 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); diff --git a/software/system/qor_armv6m.s b/software/system/qor_armv6m.s index 0d7d74a..9865201 100644 --- a/software/system/qor_armv6m.s +++ b/software/system/qor_armv6m.s @@ -20,46 +20,6 @@ @ 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 @ One limitation is the POP instruction that cannot access to the HI registers (registers after R7) -@ -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ | | -@ ------------- -@ -@ -@ -@ - qor_go: