Merge remote-tracking branch 'origin/master' into audio-stuttering-background

This commit is contained in:
jepler 2019-09-12 20:45:59 -05:00
commit 523025ce8c
38 changed files with 781 additions and 337 deletions

@ -1 +1 @@
Subproject commit 00c440cb26fbea7fd367623454d8b67855f1372f
Subproject commit f8081536310e5ac7a1e8c8ba9295890429a2cb6f

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -516,6 +516,10 @@ msgstr "Tidak bisa menyesuaikan data ke dalam paket advertisment"
msgid "Destination capacity is smaller than destination_length."
msgstr ""
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -505,6 +505,10 @@ msgstr ""
msgid "Destination capacity is smaller than destination_length."
msgstr ""
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-07-27 11:55-0700\n"
"Last-Translator: Pascal Deneaux\n"
"Language-Team: Sebastian Plamauer, Pascal Deneaux\n"
@ -509,6 +509,10 @@ msgstr "Zu vielen Daten für das advertisement packet"
msgid "Destination capacity is smaller than destination_length."
msgstr "Die Zielkapazität ist kleiner als destination_length."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-07-27 11:55-0700\n"
"Last-Translator: \n"
"Language-Team: \n"
@ -505,6 +505,10 @@ msgstr ""
msgid "Destination capacity is smaller than destination_length."
msgstr ""
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-07-27 11:55-0700\n"
"Last-Translator: \n"
"Language-Team: @sommersoft, @MrCertainly\n"
@ -509,6 +509,10 @@ msgstr ""
msgid "Destination capacity is smaller than destination_length."
msgstr ""
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-08-24 22:56-0500\n"
"Last-Translator: \n"
"Language-Team: \n"
@ -513,6 +513,10 @@ msgstr "Data es muy grande para el paquete de advertisement."
msgid "Destination capacity is smaller than destination_length."
msgstr "Capacidad de destino es mas pequeña que destination_length."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-12-20 22:15-0800\n"
"Last-Translator: Timothy <me@timothygarcia.ca>\n"
"Language-Team: fil\n"
@ -517,6 +517,10 @@ msgid "Destination capacity is smaller than destination_length."
msgstr ""
"Ang kapasidad ng destinasyon ay mas maliit kaysa sa destination_length."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2019-04-14 20:05+0100\n"
"Last-Translator: Pierrick Couturier <arofarn@arofarn.info>\n"
"Language-Team: fr\n"
@ -521,6 +521,10 @@ msgstr "Données trop volumineuses pour un paquet de diffusion"
msgid "Destination capacity is smaller than destination_length."
msgstr "La capacité de destination est plus petite que 'destination_length'."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-10-02 16:27+0200\n"
"Last-Translator: Enrico Paganin <enrico.paganin@mail.com>\n"
"Language-Team: \n"
@ -517,6 +517,10 @@ msgstr "Impossibile inserire dati nel pacchetto di advertisement."
msgid "Destination capacity is smaller than destination_length."
msgstr "La capacità di destinazione è più piccola di destination_length."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2019-03-19 18:37-0700\n"
"Last-Translator: Radomir Dopieralski <circuitpython@sheep.art.pl>\n"
"Language-Team: pl\n"
@ -508,6 +508,10 @@ msgstr "Zbyt dużo danych pakietu rozgłoszeniowego"
msgid "Destination capacity is smaller than destination_length."
msgstr "Pojemność celu mniejsza od destination_length."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2018-10-02 21:14-0000\n"
"Last-Translator: \n"
"Language-Team: \n"
@ -512,6 +512,10 @@ msgstr "Não é possível ajustar dados no pacote de anúncios."
msgid "Destination capacity is smaller than destination_length."
msgstr ""
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr ""

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: circuitpython-cn\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-29 22:16-0500\n"
"POT-Creation-Date: 2019-09-08 17:30-0500\n"
"PO-Revision-Date: 2019-04-13 10:10-0700\n"
"Last-Translator: hexthat\n"
"Language-Team: Chinese Hanyu Pinyin\n"
@ -509,6 +509,10 @@ msgstr "Guǎnggào bāo de shùjù tài dà"
msgid "Destination capacity is smaller than destination_length."
msgstr "Mùbiāo róngliàng xiǎoyú mùdì de_chángdù."
#: ports/nrf/common-hal/audiobusio/I2SOut.c
msgid "Device in use"
msgstr ""
#: shared-bindings/displayio/Display.c
msgid "Display must have a 16 bit colorspace."
msgstr "Xiǎnshì bìxū jùyǒu 16 wèi yánsè kōngjiān."

View File

@ -29,6 +29,7 @@
#include "peripheral_clk_config.h"
#include "supervisor/shared/autoreload.h"
#include "supervisor/filesystem.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Processor.h"
@ -52,10 +53,13 @@ void SysTick_Handler(void) {
(void) SysTick->CTRL;
common_hal_mcu_enable_interrupts();
#ifdef CIRCUITPY_AUTORELOAD_DELAY_MS
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
filesystem_tick();
#endif
#ifdef CIRCUITPY_AUTORELOAD_DELAY_MS
autoreload_tick();
#endif
#ifdef CIRCUITPY_GAMEPAD_TICKS
#endif
#ifdef CIRCUITPY_GAMEPAD_TICKS
if (!(ticks_ms & CIRCUITPY_GAMEPAD_TICKS)) {
#if CIRCUITPY_GAMEPAD
gamepad_tick();
@ -64,7 +68,7 @@ void SysTick_Handler(void) {
gamepadshift_tick();
#endif
}
#endif
#endif
}
void tick_init() {

View File

@ -33,6 +33,10 @@
#include "shared-module/displayio/__init__.h"
#endif
#if CIRCUITPY_AUDIOBUSIO
#include "common-hal/audiobusio/I2SOut.h"
#endif
#if CIRCUITPY_AUDIOPWMIO
#include "common-hal/audiopwmio/PWMAudioOut.h"
#endif
@ -54,6 +58,10 @@ void run_background_tasks(void) {
#if CIRCUITPY_AUDIOPWMIO
audiopwmout_background();
#endif
#if CIRCUITPY_AUDIOBUSIO
i2s_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();

View File

@ -24,47 +24,305 @@
* THE SOFTWARE.
*/
#include <math.h>
#include <string.h>
#include "common-hal/microcontroller/Pin.h"
#include "common-hal/audiobusio/I2SOut.h"
#include "shared-bindings/audiobusio/I2SOut.h"
#include "shared-module/audiocore/__init__.h"
#include "py/obj.h"
#include "py/runtime.h"
static audiobusio_i2sout_obj_t *instance;
struct { int16_t l, r; } static_sample16 = {0x8000, 0x8000};
struct { uint8_t l1, r1, l2, r2; } static_sample8 = {0x80, 0x80, 0x80, 0x80};
struct frequency_info { uint32_t RATIO; uint32_t MCKFREQ; int sample_rate; float abserr; };
struct ratio_info { uint32_t RATIO; int16_t divisor; bool can_16bit; };
struct ratio_info ratios[] = {
{ I2S_CONFIG_RATIO_RATIO_32X, 32, true },
{ I2S_CONFIG_RATIO_RATIO_48X, 48, false },
{ I2S_CONFIG_RATIO_RATIO_64X, 64, true },
{ I2S_CONFIG_RATIO_RATIO_96X, 96, true },
{ I2S_CONFIG_RATIO_RATIO_128X, 128, true },
{ I2S_CONFIG_RATIO_RATIO_192X, 192, true },
{ I2S_CONFIG_RATIO_RATIO_256X, 256, true },
{ I2S_CONFIG_RATIO_RATIO_384X, 384, true },
{ I2S_CONFIG_RATIO_RATIO_512X, 512, true },
};
struct mclk_info { uint32_t MCKFREQ; int divisor; };
struct mclk_info mclks[] = {
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV8, 8 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV10, 10 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV11, 11 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV15, 15 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV16, 16 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV21, 21 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV23, 23 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV31, 31 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV42, 42 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV63, 63 },
{ I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV125, 125 },
};
static void calculate_ratio_info(uint32_t target_sample_rate, struct frequency_info *info,
int ratio_index, int mclk_index) {
info->RATIO = ratios[ratio_index].RATIO;
info->MCKFREQ = mclks[mclk_index].MCKFREQ;
info->sample_rate = 32000000
/ ratios[ratio_index].divisor / mclks[mclk_index].divisor;
info->abserr = fabsf(1.0f * target_sample_rate - info->sample_rate)
/ target_sample_rate;
}
void choose_i2s_clocking(audiobusio_i2sout_obj_t *self, uint32_t sample_rate) {
struct frequency_info best = {0, 0, 0, 1.0};
for (size_t ri=0; ri<sizeof(ratios) / sizeof(ratios[0]); ri++) {
if (NRF_I2S->CONFIG.SWIDTH == I2S_CONFIG_SWIDTH_SWIDTH_16Bit
&& !ratios[ri].can_16bit) {
continue;
}
for (size_t mi=0; mi<sizeof(mclks) / sizeof(mclks[0]); mi++) {
struct frequency_info info = {0, 0, 1.0};
calculate_ratio_info(sample_rate, &info, ri, mi);
if (info.abserr < best.abserr) {
best = info;
}
#ifdef DEBUG_CLOCKING
mp_printf(&mp_plat_print,
"RATIO=%3d MCKFREQ=%08x rate=%d abserr=%.4f\n",
info.RATIO, info.MCKFREQ, info.sample_rate,
(double)info.abserr);
#endif
}
}
NRF_I2S->CONFIG.RATIO = best.RATIO;
NRF_I2S->CONFIG.MCKFREQ = best.MCKFREQ;
self->sample_rate = best.sample_rate;
}
static void i2s_buffer_fill(audiobusio_i2sout_obj_t* self) {
void *buffer = self->buffers[self->next_buffer];
NRF_I2S->TXD.PTR = (uintptr_t)buffer;
self->next_buffer = !self->next_buffer;
size_t bytesleft = self->buffer_length;
while (!self->paused && !self->stopping && bytesleft) {
if (self->sample_data == self->sample_end) {
uint32_t sample_buffer_length;
audioio_get_buffer_result_t get_buffer_result =
audiosample_get_buffer(self->sample, false, 0,
&self->sample_data, &sample_buffer_length);
self->sample_end = self->sample_data + sample_buffer_length;
if (get_buffer_result == GET_BUFFER_DONE) {
if (self->loop) {
audiosample_reset_buffer(self->sample, false, 0);
} else {
self->stopping = true;
break;
}
}
if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) {
self->stopping = true;
break;
}
}
uint16_t bytecount = MIN(bytesleft, (size_t)(self->sample_end - self->sample_data));
if (self->samples_signed) {
memcpy(buffer, self->sample_data, bytecount);
} else if (self->bytes_per_sample == 2) {
uint16_t *bp = (uint16_t*)buffer;
uint16_t *be = (uint16_t*)(buffer + bytecount);
uint16_t *sp = (uint16_t*)self->sample_data;
for (; bp != be; bp++) {
*bp++ = *sp++ + 0x8000;
}
} else {
uint8_t *bp = (uint8_t*)buffer;
uint8_t *be = (uint8_t*)(buffer + bytecount);
uint8_t *sp = (uint8_t*)self->sample_data;
for (; bp != be; bp++) {
*bp++ = *sp++ + 0x80;
}
}
buffer += bytecount;
self->sample_data += bytecount;
bytesleft -= bytecount;
}
// Find the last frame of real audio data and replicate its samples until
// you have 32 bits worth, which is the fundamental unit of nRF I2S DMA
if (self->bytes_per_sample == 1 && self->channel_count == 1) {
// For 8-bit mono, 4 copies of the final sample are required
self->hold_value = 0x01010101 * *(uint8_t*)(buffer-1);
} else if (self->bytes_per_sample == 2 && self->channel_count == 2) {
// For 16-bit stereo, 1 copy of the final sample is required
self->hold_value = *(uint32_t*)(buffer-4);
} else {
// For 8-bit stereo and 16-bit mono, 2 copies of the final sample are required
self->hold_value = 0x00010001 * *(uint16_t*)(buffer-2);
}
// Emulate pausing and stopping by filling the DMA buffer with copies of
// the last sample. This includes the case where this iteration of
// i2s_buffer_fill exhausted a non-looping sample.
if (self->paused || self->stopping) {
if (self->stopping) {
NRF_I2S->TASKS_STOP = 1;
self->playing = false;
}
uint32_t *bp = (uint32_t*)buffer;
uint32_t *be = (uint32_t*)(buffer + bytesleft);
for (; bp != be; )
*bp++ = self->hold_value;
return;
}
}
void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t* self,
const mcu_pin_obj_t* bit_clock, const mcu_pin_obj_t* word_select,
const mcu_pin_obj_t* data, bool left_justified) {
mp_raise_NotImplementedError(NULL);
if (instance)
mp_raise_RuntimeError(translate("Device in use"));
instance = self;
claim_pin(bit_clock);
claim_pin(word_select);
claim_pin(data);
NRF_I2S->PSEL.SCK = self->bit_clock_pin_number = bit_clock->number;
NRF_I2S->PSEL.LRCK = self->word_select_pin_number = word_select->number;
NRF_I2S->PSEL.SDOUT = self->data_pin_number = data->number;
NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master;
NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled;
NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled;
NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled;
NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit;
NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left;
NRF_I2S->CONFIG.FORMAT = left_justified ? I2S_CONFIG_FORMAT_FORMAT_Aligned
: I2S_CONFIG_FORMAT_FORMAT_I2S;
}
bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
return self->data_pin_number == 0xff;
}
void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
if (common_hal_audiobusio_i2sout_deinited(self)) {
return;
}
reset_pin_number(self->bit_clock_pin_number);
self->bit_clock_pin_number = 0xff;
reset_pin_number(self->word_select_pin_number);
self->word_select_pin_number = 0xff;
reset_pin_number(self->data_pin_number);
self->data_pin_number = 0xff;
instance = NULL;
}
void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t* self,
mp_obj_t sample, bool loop) {
mp_raise_NotImplementedError(NULL);
if (common_hal_audiobusio_i2sout_get_playing(self)) {
common_hal_audiobusio_i2sout_stop(self);
}
self->sample = sample;
self->loop = loop;
uint32_t sample_rate = audiosample_sample_rate(sample);
self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8;
uint32_t max_buffer_length;
bool single_buffer, samples_signed;
audiosample_get_buffer_structure(sample, /* single channel */ false,
&single_buffer, &samples_signed, &max_buffer_length,
&self->channel_count);
self->single_buffer = single_buffer;
self->samples_signed = samples_signed;
choose_i2s_clocking(self, sample_rate);
/* Allocate buffers based on a maximum duration
* This duration was chosen empirically based on what would
* cause os.listdir('') to cause stuttering. It seems like a
* rather long time.
*/
enum { buffer_length_ms = 16 };
self->buffer_length = sample_rate * buffer_length_ms
* self->bytes_per_sample * self->channel_count / 1000;
self->buffer_length = (self->buffer_length + 3) & ~3;
self->buffers[0] = m_malloc(self->buffer_length, false);
self->buffers[1] = m_malloc(self->buffer_length, false);
audiosample_reset_buffer(self->sample, false, 0);
self->next_buffer = 0;
self->sample_data = self->sample_end = 0;
self->playing = true;
self->paused = false;
self->stopping = false;
i2s_buffer_fill(self);
NRF_I2S->CONFIG.CHANNELS = self->channel_count == 1 ? I2S_CONFIG_CHANNELS_CHANNELS_Left : I2S_CONFIG_CHANNELS_CHANNELS_Stereo;
NRF_I2S->RXTXD.MAXCNT = self->buffer_length / 4;
NRF_I2S->ENABLE = I2S_ENABLE_ENABLE_Enabled;
NRF_I2S->TASKS_START = 1;
i2s_background();
}
void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
self->paused = true;
}
void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
self->paused = false;
}
bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
return self->paused;
}
void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
NRF_I2S->TASKS_STOP = 1;
self->stopping = true;
}
bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t* self) {
mp_raise_NotImplementedError(NULL);
if (NRF_I2S->EVENTS_STOPPED) {
self->playing = false;
NRF_I2S->EVENTS_STOPPED = 0;
}
return self->playing;
}
void i2s_background(void) {
if (NRF_I2S->EVENTS_TXPTRUPD) {
NRF_I2S->EVENTS_TXPTRUPD = 0;
if (instance) {
i2s_buffer_fill(instance);
} else {
NRF_I2S->TASKS_STOP = 1;
}
}
}
void i2s_reset(void) {
NRF_I2S->TASKS_STOP = 1;
NRF_I2S->ENABLE = I2S_ENABLE_ENABLE_Disabled;
NRF_I2S->PSEL.MCK = 0xFFFFFFFF;
NRF_I2S->PSEL.SCK = 0xFFFFFFFF;
NRF_I2S->PSEL.LRCK = 0xFFFFFFFF;
NRF_I2S->PSEL.SDOUT = 0xFFFFFFFF;
NRF_I2S->PSEL.SDIN = 0xFFFFFFFF;
instance = NULL;
}

View File

@ -31,6 +31,33 @@
typedef struct {
mp_obj_base_t base;
mp_obj_t *sample;
uint8_t *buffers[2];
uint8_t *sample_data, *sample_end;
uint16_t buffer_length;
uint16_t sample_rate;
uint32_t hold_value;
uint8_t next_buffer;
uint8_t bit_clock_pin_number;
uint8_t word_select_pin_number;
uint8_t data_pin_number;
uint8_t channel_count;
uint8_t bytes_per_sample;
bool left_justified : 1;
bool playing : 1;
bool stopping : 1;
bool paused : 1;
bool loop : 1;
bool samples_signed : 1;
bool single_buffer : 1;
} audiobusio_i2sout_obj_t;
void i2s_reset(void);
void i2s_background(void);
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_AUDIOBUSIO_I2SOUT_H

View File

@ -50,6 +50,10 @@
#include "shared-bindings/rtc/__init__.h"
#ifdef CIRCUITPY_AUDIOBUSIO
#include "common-hal/audiobusio/I2SOut.h"
#endif
#ifdef CIRCUITPY_AUDIOPWMIO
#include "common-hal/audiopwmio/PWMAudioOut.h"
#endif
@ -98,10 +102,15 @@ void reset_port(void) {
spi_reset();
uart_reset();
#ifdef CIRCUITPY_AUDIOBUSIO
i2s_reset();
#endif
#ifdef CIRCUITPY_AUDIOPWMIO
audiopwmout_reset();
#endif
#if CIRCUITPY_PULSEIO
pwmout_reset();
pulseout_reset();

View File

@ -1,71 +1,35 @@
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : Auto-generated by Ac6 System Workbench
**
** Abstract : Linker script for STM32F412ZGTx series
** 1024Kbytes FLASH and 256Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed “as is,” without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** <h2><center>&copy; COPYRIGHT(c) 2014 Ac6</center></h2>
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
** 1. Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
** 3. Neither the name of Ac6 nor the names of its contributors
** may be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*****************************************************************************
GNU linker script for STM32F412
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20040000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */
FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */
FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 48K /* sectors 1,2,3 are 16K */
FLASH_TEXT (rx) : ORIGIN = 0x08010000, LENGTH = 960K /* sector 4 is 64K, sectors 5,6,7 are 128K */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K
}
/* Define output sections */
/* produce a link error if there is not this amount of RAM for these sections */
_minimum_stack_size = 2K;
_minimum_heap_size = 16K;
/* Define tho top end of the stack. The stack is full descending so begins just
above last byte of RAM. Note that EABI requires the stack to be 8-byte
aligned for a call. */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* RAM extents for the garbage collector */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_heap_start = _ebss; /* heap starts just after statically allocated memory */
_heap_end = 0x20020000; /* tunable */
ENTRY(Reset_Handler)
/* define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
@ -73,117 +37,69 @@ SECTIONS
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
/* This first flash block is 16K annd the isr vectors only take up
about 400 bytes. Micropython pads this with files, but this didn't
work with the size of Circuitpython's ff object. */
. = ALIGN(4);
} >FLASH
} >FLASH_ISR
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
_etext = .; /* define a global symbol at end of code */
} >FLASH_TEXT
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM AT> FLASH_TEXT
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
_ebss = .; /* define a global symbol at bss end; used by startup code and GC */
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
/* this is to define the start of the heap, and make sure we have a minimum size */
.heap :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
. = ALIGN(4);
. = . + _minimum_heap_size;
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
/* this just checks there is enough RAM for the stack */
.stack :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
. = ALIGN(4);
. = . + _minimum_stack_size;
. = ALIGN(4);
} >RAM
.ARM.attributes 0 : { *(.ARM.attributes) }
}

View File

@ -1,9 +1,10 @@
USB_VID = 0x483
USB_PID = 0x572B
USB_VID = 0x239A
USB_PID = 0x8056
USB_PRODUCT = "STM32F412ZG Discovery Board - CPy"
USB_MANUFACTURER = "STMicroelectronics"
DISABLE_FILESYSTEM = 1
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
MCU_SERIES = m4
MCU_VARIANT = stm32f4

View File

@ -28,48 +28,47 @@
void stm32f4_peripherals_clocks_init(void) {
//System clock init
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the
* device is clocked below the maximum system frequency, to update the
* voltage scaling value regarding system frequency refer to product
* datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 72;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 200;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 3;
RCC_OscInitStruct.PLL.PLLQ = 7;
RCC_OscInitStruct.PLL.PLLR = 2;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
/* Select PLLSAI output as USB clock source */
PeriphClkInitStruct.PLLI2S.PLLI2SM = 8;
PeriphClkInitStruct.PLLI2S.PLLI2SQ = 4;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_CK48;
PeriphClkInitStruct.Clk48ClockSelection = RCC_CK48CLKSOURCE_PLLI2SQ;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
* clocks dividers */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S_APB1|RCC_PERIPHCLK_SDIO
|RCC_PERIPHCLK_CLK48;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 50;
PeriphClkInitStruct.PLLI2S.PLLI2SM = 4;
PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
PeriphClkInitStruct.PLLI2S.PLLI2SQ = 2;
PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48CLKSOURCE_PLLQ;
PeriphClkInitStruct.SdioClockSelection = RCC_SDIOCLKSOURCE_CLK48;
PeriphClkInitStruct.PLLI2SSelection = RCC_PLLI2SCLKSOURCE_PLLSRC;
PeriphClkInitStruct.I2sApb1ClockSelection = RCC_I2SAPB1CLKSOURCE_PLLI2S;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1);
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
}

View File

@ -34,12 +34,12 @@
#ifdef STM32F411xE
#define STM32_FLASH_SIZE 0x80000 //512KiB
#define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 //112KiB
#define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 //48KiB
#endif
#ifdef STM32F412Zx
#define STM32_FLASH_SIZE 0x100000 //1MB
#define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 //112KiB
#define INTERNAL_FLASH_FILESYSTEM_SIZE 0xC000 //48KiB
#endif
#define STM32_FLASH_OFFSET 0x8000000 //All STM32 chips map to this flash location

View File

@ -33,7 +33,8 @@
#include "stm32f4xx_hal.h"
void init_usb_hardware(void) {
// HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET); //LED 2
//TODO: if future chips overload this with options, move to peripherals management.
GPIO_InitTypeDef GPIO_InitStruct = {0};
/**USB_OTG_FS GPIO Configuration
PA10 ------> USB_OTG_FS_ID
@ -64,12 +65,14 @@ void init_usb_hardware(void) {
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#ifdef STM32F412Zx
/* Configure POWER_SWITCH IO pin (F412 ONLY)*/
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
#endif
/* Peripheral clock enable */
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
// /* Peripheral interrupt init */
// HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
//HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET); //LED 3
}

View File

@ -43,19 +43,27 @@
//|
//| Converts one color format to another.
//|
//| .. class:: ColorConverter()
//| .. class:: ColorConverter(*, dither=False)
//|
//| Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565
//| currently.
//|
//| :param bool dither: Adds random noise to dither the output image
// TODO(tannewt): Add support for other color formats.
//|
STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_check_num(n_args, kw_args, 0, 0, false);
enum { ARG_dither};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t);
self->base.type = &displayio_colorconverter_type;
common_hal_displayio_colorconverter_construct(self);
common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool);
return MP_OBJ_FROM_PTR(self);
}
@ -79,8 +87,36 @@ STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert);
//| .. attribute:: dither
//|
//| When true the color converter dithers the output by adding random noise when
//| truncating to display bitdepth
//|
STATIC mp_obj_t displayio_colorconverter_obj_get_dither(mp_obj_t self_in) {
displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(common_hal_displayio_colorconverter_get_dither(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_get_dither_obj, displayio_colorconverter_obj_get_dither);
STATIC mp_obj_t displayio_colorconverter_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) {
displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_displayio_colorconverter_set_dither(self, mp_obj_is_true(dither));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_set_dither_obj, displayio_colorconverter_obj_set_dither);
const mp_obj_property_t displayio_colorconverter_dither_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&displayio_colorconverter_get_dither_obj,
(mp_obj_t)&displayio_colorconverter_set_dither_obj,
(mp_obj_t)&mp_const_none_obj},
};
STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) },
{ MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table);
@ -90,3 +126,4 @@ const mp_obj_type_t displayio_colorconverter_type = {
.make_new = displayio_colorconverter_make_new,
.locals_dict = (mp_obj_dict_t*)&displayio_colorconverter_locals_dict,
};

View File

@ -33,7 +33,10 @@
extern const mp_obj_type_t displayio_colorconverter_type;
void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self);
void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither);
void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color);
void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither);
bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H

View File

@ -346,6 +346,9 @@ const mp_obj_property_t displayio_display_auto_brightness_obj = {
(mp_obj_t)&mp_const_none_obj},
};
//| .. attribute:: width
//|
//| Gets the width of the board

View File

@ -62,6 +62,9 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self
bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self);
void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness);
bool common_hal_displayio_display_get_dither(displayio_display_obj_t* self);
void common_hal_displayio_display_set_dither(displayio_display_obj_t* self, bool dither);
mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self);
bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness);

View File

@ -216,7 +216,7 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t*
} else {
*buffer = self->buffer;
}
if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) {
if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK || length_read != num_bytes_to_load) {
return GET_BUFFER_ERROR;
}
self->bytes_remaining -= length_read;

View File

@ -262,8 +262,8 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul) {
}
#if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU
int32_t hi, lo;
int32_t bits = 16; // saturate to 16 bits
int32_t shift = 0; // shift is done automatically
enum { bits = 16 }; // saturate to 16 bits
enum { shift = 0 }; // shift is done automatically
asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val));
asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val));
asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift));

View File

@ -28,7 +28,19 @@
#include "py/misc.h"
void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) {
uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n)
{
n = (n >> 13) ^ n;
int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return (uint32_t) (((float)nn / (1073741824.0f*2)) * 255);
}
uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) {
return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF);
}
void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) {
self->dither = dither;
}
uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) {
@ -96,34 +108,81 @@ void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* co
}
}
bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) {
if (colorspace->depth == 16) {
*output_color = displayio_colorconverter_compute_rgb565(input_color);
return true;
} else if (colorspace->tricolor) {
uint8_t luma = displayio_colorconverter_compute_luma(input_color);
*output_color = luma >> (8 - colorspace->depth);
if (displayio_colorconverter_compute_chroma(input_color) <= 16) {
if (!colorspace->grayscale) {
*output_color = 0;
}
return true;
}
uint8_t pixel_hue = displayio_colorconverter_compute_hue(input_color);
displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, output_color);
return true;
} else if (colorspace->grayscale && colorspace->depth <= 8) {
uint8_t luma = displayio_colorconverter_compute_luma(input_color);
*output_color = luma >> (8 - colorspace->depth);
return true;
}
return false;
void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) {
displayio_input_pixel_t input_pixel;
input_pixel.pixel = input_color;
input_pixel.x = input_pixel.y = input_pixel.tile = input_pixel.tile_x = input_pixel.tile_y = 0;
displayio_output_pixel_t output_pixel;
output_pixel.pixel = 0;
output_pixel.opaque = false;
displayio_colorconverter_convert(self, colorspace, &input_pixel, &output_pixel);
(*output_color) = output_pixel.pixel;
}
void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) {
displayio_colorconverter_convert(self, colorspace, input_color, output_color);
void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither) {
self->dither = dither;
}
bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self) {
return self->dither;
}
void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) {
uint32_t pixel = input_pixel->pixel;
if (self->dither){
uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y));
uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x+33,input_pixel->tile_y));
uint8_t randb = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y+33));
uint32_t r8 = (pixel >> 16);
uint32_t g8 = (pixel >> 8) & 0xff;
uint32_t b8 = pixel & 0xff;
if (colorspace->depth == 16) {
b8 = MIN(255,b8 + (randb&0x07));
r8 = MIN(255,r8 + (randr&0x07));
g8 = MIN(255,g8 + (randg&0x03));
} else {
int bitmask = 0xFF >> colorspace->depth;
b8 = MIN(255,b8 + (randb&bitmask));
r8 = MIN(255,r8 + (randr&bitmask));
g8 = MIN(255,g8 + (randg&bitmask));
}
pixel = r8 << 16 | g8 << 8 | b8;
}
if (colorspace->depth == 16) {
output_color->pixel = displayio_colorconverter_compute_rgb565(pixel);
output_color->opaque = true;
return;
} else if (colorspace->tricolor) {
uint8_t luma = displayio_colorconverter_compute_luma(pixel);
output_color->pixel = luma >> (8 - colorspace->depth);
if (displayio_colorconverter_compute_chroma(pixel) <= 16) {
if (!colorspace->grayscale) {
output_color->pixel = 0;
}
output_color->opaque = true;
return;
}
uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel);
displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, &output_color->pixel);
return;
} else if (colorspace->grayscale && colorspace->depth <= 8) {
uint8_t luma = displayio_colorconverter_compute_luma(pixel);
output_color->pixel = luma >> (8 - colorspace->depth);
output_color->opaque = true;
return;
}
output_color->opaque = false;
}
// Currently no refresh logic is needed for a ColorConverter.
bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self) {
return false;
@ -131,3 +190,4 @@ bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self) {
void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self) {
}

View File

@ -35,11 +35,16 @@
typedef struct {
mp_obj_base_t base;
bool dither;
} displayio_colorconverter_t;
bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self);
void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self);
bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color);
void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color);
uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n);
uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y);
uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888);
uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888);

View File

@ -41,6 +41,7 @@ typedef struct {
bool tricolor;
bool pixels_in_byte_share_row;
bool reverse_pixels_in_byte;
bool dither;
} _displayio_colorspace_t;
typedef struct {
@ -52,6 +53,20 @@ typedef struct {
bool transparent; // This may have additional bits added later for blending.
} _displayio_color_t;
typedef struct {
uint32_t pixel;
uint16_t x;
uint16_t y;
uint8_t tile;
uint16_t tile_x;
uint16_t tile_y;
} displayio_input_pixel_t;
typedef struct {
uint32_t pixel;
bool opaque;
} displayio_output_pixel_t;
typedef struct {
mp_obj_base_t base;
_displayio_color_t* colors;

View File

@ -396,12 +396,16 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c
}
uint8_t pixels_per_byte = 8 / colorspace->depth;
for (int16_t y = start_y; y < end_y; y++) {
int16_t row_start = start + (y - start_y + y_shift) * y_stride; // in pixels
int16_t local_y = y / self->absolute_transform->scale;
for (int16_t x = start_x; x < end_x; x++) {
displayio_input_pixel_t input_pixel;
displayio_output_pixel_t output_pixel;
for (input_pixel.y = start_y; input_pixel.y < end_y; ++input_pixel.y) {
int16_t row_start = start + (input_pixel.y - start_y + y_shift) * y_stride; // in pixels
int16_t local_y = input_pixel.y / self->absolute_transform->scale;
for (input_pixel.x = start_x; input_pixel.x < end_x; ++input_pixel.x) {
// Compute the destination pixel in the buffer and mask based on the transformations.
int16_t offset = row_start + (x - start_x + x_shift) * x_stride; // in pixels
int16_t offset = row_start + (input_pixel.x - start_x + x_shift) * x_stride; // in pixels
// This is super useful for debugging out of range accesses. Uncomment to use.
// if (offset < 0 || offset >= (int32_t) displayio_area_size(area)) {
@ -412,41 +416,43 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c
if ((mask[offset / 32] & (1 << (offset % 32))) != 0) {
continue;
}
int16_t local_x = x / self->absolute_transform->scale;
int16_t local_x = input_pixel.x / self->absolute_transform->scale;
uint16_t tile_location = ((local_y / self->tile_height + self->top_left_y) % self->height_in_tiles) * self->width_in_tiles + (local_x / self->tile_width + self->top_left_x) % self->width_in_tiles;
uint8_t tile = tiles[tile_location];
uint16_t tile_x = (tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width;
uint16_t tile_y = (tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height;
input_pixel.tile = tiles[tile_location];
input_pixel.tile_x = (input_pixel.tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width;
input_pixel.tile_y = (input_pixel.tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height;
//uint32_t value = 0;
output_pixel.pixel = 0;
input_pixel.pixel = 0;
uint32_t value = 0;
// We always want to read bitmap pixels by row first and then transpose into the destination
// buffer because most bitmaps are row associated.
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
value = common_hal_displayio_bitmap_get_pixel(self->bitmap, tile_x, tile_y);
input_pixel.pixel = common_hal_displayio_bitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) {
value = common_hal_displayio_shape_get_pixel(self->bitmap, tile_x, tile_y);
input_pixel.pixel = common_hal_displayio_shape_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) {
value = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, tile_x, tile_y);
input_pixel.pixel = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y);
}
uint32_t pixel;
bool opaque = true;
output_pixel.opaque = true;
if (self->pixel_shader == mp_const_none) {
pixel = value;
output_pixel.pixel = input_pixel.pixel;
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) {
opaque = displayio_palette_get_color(self->pixel_shader, colorspace, value, &pixel);
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) {
opaque = displayio_colorconverter_convert(self->pixel_shader, colorspace, value, &pixel);
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
}
if (!opaque) {
if (!output_pixel.opaque) {
// A pixel is transparent so we haven't fully covered the area ourselves.
full_coverage = false;
} else {
mask[offset / 32] |= 1 << (offset % 32);
if (colorspace->depth == 16) {
*(((uint16_t*) buffer) + offset) = pixel;
*(((uint16_t*) buffer) + offset) = output_pixel.pixel;
} else if (colorspace->depth == 8) {
*(((uint8_t*) buffer) + offset) = pixel;
*(((uint8_t*) buffer) + offset) = output_pixel.pixel;
} else if (colorspace->depth < 8) {
// Reorder the offsets to pack multiple rows into a byte (meaning they share a column).
if (!colorspace->pixels_in_byte_share_row) {
@ -465,7 +471,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c
// Reverse the shift by subtracting it from the leftmost shift.
shift = (pixels_per_byte - 1) * colorspace->depth - shift;
}
((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << shift;
((uint8_t*)buffer)[offset / pixels_per_byte] |= output_pixel.pixel << shift;
}
}
}

View File

@ -49,6 +49,7 @@ void displayio_display_core_construct(displayio_display_core_t* self,
self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row;
self->colorspace.bytes_per_cell = bytes_per_cell;
self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte;
self->colorspace.dither = false;
self->current_group = NULL;
self->colstart = colstart;
self->rowstart = rowstart;
@ -172,6 +173,14 @@ uint16_t displayio_display_core_get_height(displayio_display_core_t* self){
return self->height;
}
void displayio_display_core_set_dither(displayio_display_core_t* self, bool dither){
self->colorspace.dither = dither;
}
bool displayio_display_core_get_dither(displayio_display_core_t* self){
return self->colorspace.dither;
}
bool displayio_display_core_bus_free(displayio_display_core_t *self) {
return self->bus_free(self->bus);
}

View File

@ -65,6 +65,9 @@ bool displayio_display_core_show(displayio_display_core_t* self, displayio_group
uint16_t displayio_display_core_get_width(displayio_display_core_t* self);
uint16_t displayio_display_core_get_height(displayio_display_core_t* self);
void displayio_display_core_set_dither(displayio_display_core_t* self, bool dither);
bool displayio_display_core_get_dither(displayio_display_core_t* self);
bool displayio_display_core_bus_free(displayio_display_core_t *self);
bool displayio_display_core_begin_transaction(displayio_display_core_t* self);
void displayio_display_core_end_transaction(displayio_display_core_t* self);

View File

@ -428,6 +428,7 @@ static bool flush_ram_cache(bool keep_cache) {
}
// Delegates to the correct flash flush method depending on the existing cache.
// TODO Don't blink the status indicator if we don't actually do any writing (hard to tell right now).
static void spi_flash_flush_keep_cache(bool keep_cache) {
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);

View File

@ -266,9 +266,15 @@ void temp_status_color(uint32_t rgb) {
void clear_temp_status() {
#ifdef MICROPY_HW_NEOPIXEL
if (neopixel_in_use) {
return;
}
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (apa102_mosi_in_use || apa102_sck_in_use) {
return;
}
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#else

View File

@ -173,17 +173,21 @@ msc_interfaces = [
# args.hid_devices[1] has report_id 2
# etc.
report_ids = {}
if len(args.hid_devices) == 1:
name = args.hid_devices[0]
combined_hid_report_descriptor = hid.ReportDescriptor(
description=name,
report_descriptor=bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](0)))
report_ids[name] = 0
else:
report_id = 1
concatenated_descriptors = bytearray()
for name in args.hid_devices:
concatenated_descriptors.extend(
bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](report_id)))
report_ids[name] = report_id
report_id += 1
combined_hid_report_descriptor = hid.ReportDescriptor(
description="MULTIDEVICE",
@ -288,10 +292,24 @@ audio_control_interface = standard.InterfaceDescriptor(
# Audio streaming interfaces must occur before MIDI ones.
audio_interfaces = [audio_control_interface] + cs_ac_interface.audio_streaming_interfaces + cs_ac_interface.midi_streaming_interfaces
# This will renumber the endpoints to make them unique across descriptors,
interfaces_to_join = []
if 'CDC' in args.devices:
interfaces_to_join.append(cdc_interfaces)
if 'MSC' in args.devices:
interfaces_to_join.append(msc_interfaces)
if 'HID' in args.devices:
interfaces_to_join.append(hid_interfaces)
if 'AUDIO' in args.devices:
interfaces_to_join.append(audio_interfaces)
# util.join_interfaces() will renumber the endpoints to make them unique across descriptors,
# and renumber the interfaces in order. But we still need to fix up certain
# interface cross-references.
interfaces = util.join_interfaces(cdc_interfaces, msc_interfaces, hid_interfaces, audio_interfaces)
interfaces = util.join_interfaces(*interfaces_to_join)
# Now adjust the CDC interface cross-references.
@ -323,13 +341,15 @@ if 'CDC' in args.devices:
if 'MSC' in args.devices:
descriptor_list.extend(msc_interfaces)
if 'HID' in args.devices:
descriptor_list.extend(hid_interfaces)
if 'AUDIO' in args.devices:
# Only add the control interface because other audio interfaces are managed by it to ensure the
# correct ordering.
descriptor_list.append(audio_control_interface)
if 'HID' in args.devices:
descriptor_list.extend(hid_interfaces)
# Finally, build the composite descriptor.
configuration = standard.ConfigurationDescriptor(
description="Composite configuration",
@ -502,7 +522,7 @@ c_file.write("""\
""")
# Write out USB HID report buffer definitions.
for report_id, name in enumerate(args.hid_devices, start=1):
for name in args.hid_devices:
c_file.write("""\
static uint8_t {name}_report_buffer[{report_length}];
""".format(name=name.lower(), report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length))
@ -511,18 +531,18 @@ static uint8_t {name}_report_buffer[{report_length}];
c_file.write("""
usb_hid_device_obj_t usb_hid_devices[] = {
""");
for report_id, name in enumerate(args.hid_devices, start=1):
for name in args.hid_devices:
device_data = hid_report_descriptors.HID_DEVICE_DATA[name]
c_file.write("""\
{{
.base = {{ .type = &usb_hid_device_type }},
.report_buffer = {name}_report_buffer,
.report_id = {report_id:},
.report_id = {report_id},
.report_length = {report_length},
.usage_page = {usage_page:#04x},
.usage = {usage:#04x},
}},
""".format(name=name.lower(), report_id=report_id,
""".format(name=name.lower(), report_id=report_ids[name],
report_length=device_data.report_length,
usage_page=device_data.usage_page,
usage=device_data.usage))