Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5296241949 | ||
|
|
d84ff02f03 | ||
|
|
cc2581afd6 | ||
|
|
bb682bbb33 | ||
|
|
809beffc8b | ||
|
|
fa22c6c627 | ||
|
|
0788a42477 | ||
|
|
d732ac82ba | ||
|
|
5fb5e16be8 | ||
|
|
45c0b3a1b4 | ||
|
|
7961d2943d | ||
|
|
4d03edc7d5 | ||
|
|
d5a6888cac | ||
|
|
a13d236afd |
@@ -196,7 +196,7 @@ jobs:
|
||||
name: Mac
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-12, macOS-14]
|
||||
os: [macOS-13, macOS-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -3,5 +3,7 @@ system
|
||||
tools/dist
|
||||
docs/_build
|
||||
ota/build
|
||||
ota/build-rp2350
|
||||
ota/build-rp2350-riscv
|
||||
tools/libpico/build
|
||||
platform.local.txt
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ sphinx:
|
||||
# fail_on_warning: true
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
formats:
|
||||
- pdf
|
||||
formats:
|
||||
- pdf
|
||||
# - epub
|
||||
|
||||
# Optional but recommended, declare the Python requirements required
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 4
|
||||
#define ARDUINO_PICO_MINOR 4
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "4.4.0"
|
||||
#define ARDUINO_PICO_REVISION 1
|
||||
#define ARDUINO_PICO_VERSION_STR "4.4.1"
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'4.4.0'
|
||||
version = u'4.4.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'4.4.0'
|
||||
release = u'4.4.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -143,15 +143,19 @@ it using the ``mklittlefs`` tool. A working ``OpenOCD`` setup, DebugProbe, and
|
||||
To download the raw filesystem, from within ``GDB`` run:
|
||||
|
||||
.. code::
|
||||
|
||||
^C (break)
|
||||
(gdb) dump binary memory littlefs.bin &_FS_start &_FS_end
|
||||
|
||||
It may take a few seconds as ``GDB`` reads out the flash to the file. Once the raw file is downloaded it can be extracted using the ``mklittlefs`` tool from the BASH/Powershell/command line
|
||||
|
||||
.. code::
|
||||
|
||||
$ <path-to-mklittlefs>/mklittlefs -u output-dir littlefs.bin
|
||||
Directory <output-dir> does not exists. Try to create it.
|
||||
gmon.out > <output-dir>/gmon.out size: 24518 Bytes
|
||||
gmon.bak > <output-dir>/gmon.bak size: 1 Bytes
|
||||
|
||||
The defaults built into ``mklittlefs`` should be appropriate for normal LittleFS filesystems built on the device or using the upload tool.
|
||||
|
||||
SD Library Information
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ sample rate on-the-fly.
|
||||
bool setSysClk(int samplerate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Changes the PICO system clock to optimise for the desired samplerate.
|
||||
The clock changes to 147.6 MHz for samplerates that are a multiple of 8 kHz, and 135.6 MHz for multiples of 11.025 kHz.
|
||||
The clock changes to 153.6 MHz for samplerates that are a multiple of 8 kHz, and 135.6 MHz for multiples of 11.025 kHz.
|
||||
Note that using ``setSysClk()`` may affect the timing of other sysclk-dependent functions.
|
||||
Should be called before any I2S functions and any other sysclk dependent initialisations.
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ File KEYWORD1
|
||||
timeval KEYWORD1
|
||||
time_t KEYWORD1
|
||||
SoftwareSerial KEYWORD1
|
||||
AudioOutputBase KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -188,6 +188,39 @@ bool AudioBufferManager::write(uint32_t v, bool sync) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t AudioBufferManager::write(const uint32_t *v, size_t words, bool sync) {
|
||||
size_t written = 0;
|
||||
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
while (words) {
|
||||
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_empty;
|
||||
if (!*p) {
|
||||
if (!sync) {
|
||||
return written;
|
||||
} else {
|
||||
while (!*p) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
size_t availToWriteThisBuff = _wordsPerBuffer - _userOff;
|
||||
size_t toWrite = std::min(availToWriteThisBuff, words);
|
||||
memcpy(&((*p)->buff[_userOff]), v, toWrite * sizeof(uint32_t));
|
||||
v += toWrite;
|
||||
written += toWrite;
|
||||
_userOff += toWrite;
|
||||
words -= toWrite;
|
||||
if (_userOff == _wordsPerBuffer) {
|
||||
_addToList(&_filled, _takeFromList(p));
|
||||
_userOff = 0;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
bool AudioBufferManager::read(uint32_t *v, bool sync) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
bool begin(int dreq, volatile void *pioFIFOAddr);
|
||||
|
||||
bool write(uint32_t v, bool sync = true);
|
||||
size_t write(const uint32_t *v, size_t words, bool sync = true);
|
||||
bool read(uint32_t *v, bool sync = true);
|
||||
void flush();
|
||||
|
||||
|
||||
@@ -123,12 +123,10 @@ bool I2S::setFrequency(int newFreq) {
|
||||
|
||||
bool I2S::setSysClk(int samplerate) { // optimise sys_clk for desired samplerate
|
||||
if (samplerate % 11025 == 0) {
|
||||
set_sys_clock_khz(I2SSYSCLK_44_1, false); // 147.6 unsuccessful - no I2S no USB
|
||||
return true;
|
||||
return set_sys_clock_khz(I2SSYSCLK_44_1, false);
|
||||
}
|
||||
if (samplerate % 8000 == 0) {
|
||||
set_sys_clock_khz(I2SSYSCLK_8, false);
|
||||
return true;
|
||||
return set_sys_clock_khz(I2SSYSCLK_8, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -502,20 +500,7 @@ size_t I2S::write(const uint8_t *buffer, size_t size) {
|
||||
if (size & 0x3 || !_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t writtenSize = 0;
|
||||
uint32_t *p = (uint32_t *)buffer;
|
||||
while (size) {
|
||||
if (!_arb->write(*p, false)) {
|
||||
// Blocked, stop write here
|
||||
return writtenSize;
|
||||
} else {
|
||||
p++;
|
||||
size -= 4;
|
||||
writtenSize += 4;
|
||||
}
|
||||
}
|
||||
return writtenSize;
|
||||
return _arb->write((const uint32_t *)buffer, size / sizeof(uint32_t), false);
|
||||
}
|
||||
|
||||
int I2S::availableForWrite() {
|
||||
|
||||
@@ -163,5 +163,5 @@ private:
|
||||
int _sm, _smMCLK;
|
||||
|
||||
static const int I2SSYSCLK_44_1 = 135600; // 44.1, 88.2 kHz sample rates
|
||||
static const int I2SSYSCLK_8 = 147600; // 8k, 16, 32, 48, 96, 192 kHz
|
||||
static const int I2SSYSCLK_8 = 153600; // 8k, 16, 32, 48, 96, 192 kHz
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "PWMAudio.h"
|
||||
#include "PWMAudioPrecalc.h"
|
||||
#include <hardware/pwm.h>
|
||||
|
||||
|
||||
@@ -100,7 +101,8 @@ bool PWMAudio::setFrequency(int frequency) {
|
||||
return true; // We're already at the right speed
|
||||
}
|
||||
if (_pacer < 0) {
|
||||
return false;
|
||||
_sampleRate = frequency;
|
||||
return true;
|
||||
}
|
||||
uint16_t _pacer_D, _pacer_N;
|
||||
// Flip fraction(N for D, D for N) because we are using it as sys_clk * fraction(mechanic of dma_timer_set_fraction) for smaller than sys_clk values
|
||||
@@ -151,6 +153,7 @@ bool PWMAudio::begin() {
|
||||
if (_pacer < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t _pacer_D = 0;
|
||||
uint16_t _pacer_N = 0;
|
||||
// Flip fraction(N for D, D for N) because we are using it as sys_clk * fraction(mechanic of dma_timer_set_fraction) for smaller than sys_clk values
|
||||
@@ -281,6 +284,19 @@ void PWMAudio::find_pacer_fraction(int target, uint16_t *numerator, uint16_t *de
|
||||
return;
|
||||
}
|
||||
|
||||
// See if it's one of the precalculated values
|
||||
for (size_t i = 0; i < sizeof(__PWMAudio_pacer) / sizeof(__PWMAudio_pacer[0]); i++) {
|
||||
if (target == (int)__PWMAudio_pacer[i].freq) {
|
||||
last_target = target;
|
||||
bestNum = __PWMAudio_pacer[i].n;
|
||||
bestDenom = __PWMAudio_pacer[i].d;
|
||||
*numerator = bestNum;
|
||||
*denominator = bestDenom;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Nope, do exhaustive search. This is gonna be slooooow
|
||||
float targetRatio = (float)F_CPU / target;
|
||||
float lowestError = HUGE_VALF;
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Generated by tools/makepacer.cpp, do not edit
|
||||
typedef struct {
|
||||
uint32_t freq;
|
||||
uint16_t n;
|
||||
uint16_t d;
|
||||
} PWMPacerPrecalc;
|
||||
#if F_CPU == 50000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 6250, 1}, {11025, 31746, 7}, {16000, 3125, 1}, {22050, 15873, 7}, {32000, 3125, 2}, {44100, 53288, 47}, {48000, 3125, 3}, {88200, 42517, 75}, {96000, 3125, 6}, {176400, 55839, 197}, {192000, 3125, 12}};
|
||||
#elif F_CPU == 100000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 12500, 1}, {11025, 63492, 7}, {16000, 6250, 1}, {22050, 31746, 7}, {32000, 3125, 1}, {44100, 15873, 7}, {48000, 6250, 3}, {88200, 53288, 47}, {96000, 3125, 3}, {176400, 42517, 75}, {192000, 3125, 6}};
|
||||
#elif F_CPU == 120000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 15000, 1}, {11025, 32653, 3}, {16000, 7500, 1}, {22050, 59864, 11}, {32000, 3750, 1}, {44100, 62585, 23}, {48000, 2500, 1}, {88200, 62585, 46}, {96000, 1250, 1}, {176400, 62585, 92}, {192000, 625, 1}};
|
||||
#elif F_CPU == 125000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 15625, 1}, {11025, 56689, 5}, {16000, 15625, 2}, {22050, 62358, 11}, {32000, 15625, 4}, {44100, 42517, 15}, {48000, 15625, 6}, {88200, 42517, 30}, {96000, 15625, 12}, {176400, 42517, 60}, {192000, 15625, 24}};
|
||||
#elif F_CPU == 128000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 16000, 1}, {11025, 11610, 1}, {16000, 8000, 1}, {22050, 5805, 1}, {32000, 4000, 1}, {44100, 5805, 2}, {48000, 8000, 3}, {88200, 5805, 4}, {96000, 4000, 3}, {176400, 61678, 85}, {192000, 2000, 3}};
|
||||
#elif F_CPU == 133000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 16625, 1}, {11025, 24127, 2}, {16000, 16625, 2}, {22050, 24127, 4}, {32000, 16625, 4}, {44100, 24127, 8}, {48000, 16625, 6}, {88200, 24127, 16}, {96000, 16625, 12}, {176400, 47500, 63}, {192000, 16625, 24}};
|
||||
#elif F_CPU == 150000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 18750, 1}, {11025, 27211, 2}, {16000, 9375, 1}, {22050, 47619, 7}, {32000, 9375, 2}, {44100, 37415, 11}, {48000, 3125, 1}, {88200, 42517, 25}, {96000, 3125, 2}, {176400, 42517, 50}, {192000, 3125, 4}};
|
||||
#elif F_CPU == 175000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 21875, 1}, {11025, 15873, 1}, {16000, 21875, 2}, {22050, 15873, 2}, {32000, 21875, 4}, {44100, 15873, 4}, {48000, 21875, 6}, {88200, 15873, 8}, {96000, 21875, 12}, {176400, 62500, 63}, {192000, 21875, 24}};
|
||||
#elif F_CPU == 200000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 25000, 1}, {11025, 54422, 3}, {16000, 12500, 1}, {22050, 63492, 7}, {32000, 6250, 1}, {44100, 31746, 7}, {48000, 12500, 3}, {88200, 15873, 7}, {96000, 6250, 3}, {176400, 53288, 47}, {192000, 3125, 3}};
|
||||
#elif F_CPU == 225000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 28125, 1}, {11025, 20408, 1}, {16000, 28125, 2}, {22050, 10204, 1}, {32000, 28125, 4}, {44100, 5102, 1}, {48000, 9375, 2}, {88200, 63776, 25}, {96000, 9375, 4}, {176400, 62500, 49}, {192000, 9375, 8}};
|
||||
#elif F_CPU == 240000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 30000, 1}, {11025, 65306, 3}, {16000, 15000, 1}, {22050, 32653, 3}, {32000, 7500, 1}, {44100, 59864, 11}, {48000, 5000, 1}, {88200, 62585, 23}, {96000, 2500, 1}, {176400, 62585, 46}, {192000, 1250, 1}};
|
||||
#elif F_CPU == 250000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 31250, 1}, {11025, 45351, 2}, {16000, 15625, 1}, {22050, 56689, 5}, {32000, 15625, 2}, {44100, 62358, 11}, {48000, 15625, 3}, {88200, 42517, 15}, {96000, 15625, 6}, {176400, 42517, 30}, {192000, 15625, 12}};
|
||||
#elif F_CPU == 275000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 34375, 1}, {11025, 49887, 2}, {16000, 34375, 2}, {22050, 37415, 3}, {32000, 34375, 4}, {44100, 37415, 6}, {48000, 34375, 6}, {88200, 37415, 12}, {96000, 34375, 12}, {176400, 35856, 23}, {192000, 34375, 24}};
|
||||
#elif F_CPU == 300000000
|
||||
static const PWMPacerPrecalc __PWMAudio_pacer[] = {{8000, 37500, 1}, {11025, 27211, 1}, {16000, 18750, 1}, {22050, 27211, 2}, {32000, 9375, 1}, {44100, 47619, 7}, {48000, 6250, 1}, {88200, 37415, 11}, {96000, 3125, 1}, {176400, 42517, 25}, {192000, 3125, 2}};
|
||||
#else
|
||||
const PWMPacerPrecalc __PWMAudio_pacer[] = {{1, 1, 1}}; // Invalid, should never match
|
||||
#endif
|
||||
+10
-1
@@ -63,6 +63,8 @@ target_compile_definitions(ota PUBLIC
|
||||
PICO_RP2040_B2_SUPPORTED=1
|
||||
PICO_PRINTF_SUPPORT_FLOAT=0
|
||||
PICO_PRINTF_SUPPORT_LONG_LONG=0
|
||||
PICO_RUNTIME_INIT_AEABI_BIT_OPS=00090
|
||||
PICO_RUNTIME_INIT_AEABI_MEM_OPS=00091
|
||||
LIB_PICO_PRINTF_NONE=1
|
||||
LFS_READONLY=1
|
||||
LFS_NO_DEBUG=1
|
||||
@@ -112,5 +114,12 @@ target_link_libraries(ota
|
||||
add_custom_command(TARGET ota POST_BUILD
|
||||
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-ld -r -A ${OBJARCH} -b binary -o ota.o ota.bin
|
||||
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o
|
||||
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
|
||||
)
|
||||
|
||||
if(NOT ${cpu} MATCHES "rp2350-riscv$")
|
||||
# riscv build uses the same include directories in lib/rp2350-riscv/platform_inc.txt
|
||||
# so we don't copy in that case
|
||||
add_custom_command(TARGET ota POST_BUILD
|
||||
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <hardware/sync.h>
|
||||
#include <hardware/flash.h>
|
||||
#include <pico/time.h>
|
||||
#include <pico/runtime_init.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/uart.h>
|
||||
#include <hardware/watchdog.h>
|
||||
@@ -54,26 +55,33 @@ void dumphex(uint32_t x) {
|
||||
}
|
||||
|
||||
extern OTACmdPage _ota_cmd;
|
||||
void do_ota() {
|
||||
static uint32_t blockToErase;
|
||||
|
||||
|
||||
bool has_ota() {
|
||||
if (*__FS_START__ == *__FS_END__) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!lfsMount(*__FS_START__, 4096, *__FS_END__ - *__FS_START__)) {
|
||||
uart_puts(uart0, "mount failed\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We are very naughty and record the last block read, since it should be the actual data block of the
|
||||
// OTA structure. We'll erase it behind the scenes to avoid bringing in all of LittleFS write infra.
|
||||
uint32_t blockToErase;
|
||||
if (!lfsReadOTA(&_ota_cmd, &blockToErase)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(_ota_cmd.sign, "Pico OTA", 8)) {
|
||||
return; // No signature
|
||||
return false; // No signature
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void do_ota() {
|
||||
uint32_t crc = 0xffffffff;
|
||||
const uint8_t *data = (const uint8_t *)&_ota_cmd;
|
||||
for (uint32_t i = 0; i < offsetof(OTACmdPage, crc32); i++) {
|
||||
@@ -159,11 +167,48 @@ void do_ota() {
|
||||
|
||||
// Do a hard reset just in case the start up sequence is not the same
|
||||
watchdog_reboot(0, 0, 100);
|
||||
while (true) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
__attribute__((noreturn))
|
||||
void boot_normal() {
|
||||
#ifdef __riscv
|
||||
extern void __mainapp();
|
||||
__mainapp();
|
||||
#else
|
||||
// Reset the interrupt/etc. vectors to the real app. Will be copied to RAM in app's runtime_init
|
||||
scb_hw->vtor = (uint32_t)0x10003000;
|
||||
|
||||
// Jump to it
|
||||
register uint32_t* sp asm("sp");
|
||||
register uint32_t _sp = *(uint32_t *)0x10003000;
|
||||
register void (*fcn)(void) = (void (*)(void)) *(uint32_t *)0x10003004;
|
||||
sp = (uint32_t *)_sp;
|
||||
fcn();
|
||||
(void)sp;
|
||||
#endif
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void check_ota() {
|
||||
// this runs before the full runtime and hardware is initialized to prevent
|
||||
// initialization happening again in the application. Care must be taken that
|
||||
// no uninitialized peripheral or part of the runtime is used.
|
||||
// If necessary, init routines can be moved before check_ota() by adjusting
|
||||
// their PICO_RUNTIME_INIT_* in CMakeLists.txt.
|
||||
// refer to this source for existing init routines:
|
||||
// https://github.com/raspberrypi/pico-sdk/blob/2.1.0/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h
|
||||
if (!has_ota()) {
|
||||
boot_normal();
|
||||
}
|
||||
}
|
||||
PICO_RUNTIME_INIT_FUNC_RUNTIME(check_ota, "00099");
|
||||
|
||||
int main(int a, char **b) {
|
||||
(void) a;
|
||||
(void) b;
|
||||
@@ -176,28 +221,11 @@ int main(int a, char **b) {
|
||||
uart_set_format(uart0, 8, 1, UART_PARITY_NONE);
|
||||
#endif
|
||||
|
||||
// if we arrive here, it looks like we have an OTA command in the LittleFS
|
||||
do_ota();
|
||||
|
||||
#ifdef __riscv
|
||||
extern void __mainapp();
|
||||
__mainapp();
|
||||
|
||||
// Should never get here!
|
||||
return 0;
|
||||
#else
|
||||
// Reset the interrupt/etc. vectors to the real app. Will be copied to RAM in app's runtime_init
|
||||
scb_hw->vtor = (uint32_t)0x10003000;
|
||||
|
||||
// Jump to it
|
||||
register uint32_t* sp asm("sp");
|
||||
register uint32_t _sp = *(uint32_t *)0x10003000;
|
||||
register void (*fcn)(void) = (void (*)(void)) *(uint32_t *)0x10003004;
|
||||
sp = (uint32_t *)_sp;
|
||||
fcn();
|
||||
|
||||
// Should never get here!
|
||||
return *sp;
|
||||
#endif
|
||||
// fallback to normal boot if do_ota() failed, e.g. due to CRC failure or corruption
|
||||
boot_normal();
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.40400.0",
|
||||
"version": "1.40401.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040, RP2350)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||
|
||||
name=Raspberry Pi RP2040/RP2350 Boards
|
||||
version=4.4.0
|
||||
version=4.4.1
|
||||
|
||||
# Required discoveries and monitors
|
||||
# ---------------------------------
|
||||
|
||||
@@ -312,8 +312,8 @@ target_link_libraries(ipv4-ipv6-bt-big-${cpu}
|
||||
|
||||
foreach(tgt pico ipv4 ipv4-ipv6 ipv4-big ipv4-ipv6-big ipv4-bt ipv4-ipv6-bt ipv4-bt-big ipv4-ipv6-bt-big)
|
||||
add_custom_command(TARGET ${tgt}-${cpu} POST_BUILD
|
||||
COMMAND ar d lib${tgt}-${cpu}.a stdio.c.obj stdio_uart.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj pico_malloc.c.obj newlib_interface.c.obj
|
||||
COMMAND ar d lib${tgt}-${cpu}.a btstack_flash_bank.c.obj # Need to override with our own implementation
|
||||
COMMAND arm-none-eabi-ar d lib${tgt}-${cpu}.a stdio.c.obj stdio_uart.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj pico_malloc.c.obj newlib_interface.c.obj
|
||||
COMMAND arm-none-eabi-ar d lib${tgt}-${cpu}.a btstack_flash_bank.c.obj # Need to override with our own implementation
|
||||
COMMAND cp lib${tgt}-${cpu}.a ../../../lib/${cpu}/lib${tgt}.a
|
||||
)
|
||||
endforeach()
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// Generates a header with precalculated best dividers for PWMAudio at
|
||||
// standard clock frequencies and audio rates.
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
void find_pacer_fraction(int F_CPU, int target, uint16_t *numerator, uint16_t *denominator) {
|
||||
const uint16_t max = 0xFFFF;
|
||||
|
||||
/*Cache last results so we dont have to recalculate*/
|
||||
static int last_target;
|
||||
static uint16_t bestNum;
|
||||
static uint16_t bestDenom;
|
||||
/*Check if we can load the previous values*/
|
||||
if (target == last_target) {
|
||||
*numerator = bestNum;
|
||||
*denominator = bestDenom;
|
||||
return;
|
||||
}
|
||||
|
||||
float targetRatio = (float)F_CPU / target;
|
||||
float lowestError = 10000000;
|
||||
|
||||
for (uint16_t denom = 1; denom < max; denom++) {
|
||||
uint16_t num = (int)((targetRatio * denom) + 0.5f); /*Calculate numerator, rounding to nearest integer*/
|
||||
|
||||
/*Check if numerator is within bounds*/
|
||||
if (num > 0 && num < max) {
|
||||
float actualRatio = (float)num / denom;
|
||||
float error = fabsf(actualRatio - targetRatio);
|
||||
|
||||
if (error < lowestError) {
|
||||
bestNum = num;
|
||||
bestDenom = denom;
|
||||
lowestError = error;
|
||||
if (error == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_target = target;
|
||||
*numerator = bestNum;
|
||||
*denominator = bestDenom;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
int M = 1000000;
|
||||
int fsys[] = {50*M, 100*M, 120*M, 125*M, 128*M, 133*M, 150*M, 175*M, 200*M, 225*M, 240*M, 250*M, 275*M, 300*M};
|
||||
int freq[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000};
|
||||
FILE *f = fopen("../libraries/PWMAudio/src/PWMAudioPrecalc.h", "w");
|
||||
fprintf(f, "// Generated by tools/makepacer.cpp, do not edit\n");
|
||||
fprintf(f, "typedef struct {\n");
|
||||
fprintf(f, " uint32_t freq;\n");
|
||||
fprintf(f, " uint16_t n;\n");
|
||||
fprintf(f, " uint16_t d;\n");
|
||||
fprintf(f, "} PWMPacerPrecalc;\n");
|
||||
for (int i = 0; i < sizeof(fsys)/sizeof(fsys[0]); i++) {
|
||||
fprintf(f, "#%s F_CPU == %d\n", i == 0 ? "if" : "elif", fsys[i]);
|
||||
fprintf(f, "static const PWMPacerPrecalc __PWMAudio_pacer[] = {");
|
||||
for (int j = 0; j < sizeof(freq)/sizeof(freq[0]); j++) {
|
||||
uint16_t n, d;
|
||||
find_pacer_fraction(fsys[i], freq[j], &n, &d);
|
||||
fprintf(f, "{%d, %d, %d}", freq[j], n, d);
|
||||
if (j < sizeof(freq)/sizeof(freq[0]) - 1) {
|
||||
fprintf(f, ", ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "};\n");
|
||||
}
|
||||
fprintf(f, "#else\n");
|
||||
fprintf(f, "const PWMPacerPrecalc __PWMAudio_pacer[] = {{1, 1, 1}}; // Invalid, should never match\n");
|
||||
fprintf(f, "#endif\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ static const uint8_t D18 = (9u);
|
||||
|
||||
// LEDs
|
||||
#define PIN_LED (25u)
|
||||
#define LED_BUILTIN PIN_LED
|
||||
|
||||
// Serial
|
||||
#define PIN_SERIAL1_TX (0u)
|
||||
|
||||
Reference in New Issue
Block a user