Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20cabe824f | ||
|
|
0847d3dbb0 | ||
|
|
fa7c287f07 | ||
|
|
9b3032cd58 | ||
|
|
50646b9e70 | ||
|
|
3d6a1c7b41 | ||
|
|
5b76b0668b | ||
|
|
d18f8dce2f | ||
|
|
c64cdc14b6 | ||
|
|
cc800713bd | ||
|
|
c6a0d6ecfe | ||
|
|
c6426ae461 | ||
|
|
7b04a033b3 | ||
|
|
8e4008bf12 | ||
|
|
7eb176c0b4 | ||
|
|
3f475ac68c | ||
|
|
5204dab99b | ||
|
|
273fb84dc5 | ||
|
|
fe3af4d98b | ||
|
|
9aade5bb24 | ||
|
|
3c408dab7c | ||
|
|
2888f4d03d | ||
|
|
f57b5bc762 | ||
|
|
35a4d57360 | ||
|
|
579e366bcf | ||
|
|
db4f79448d | ||
|
|
45bbcca207 | ||
|
|
8e961a5667 | ||
|
|
64ad69c247 | ||
|
|
4def2f219c | ||
|
|
b2b4b2d71d | ||
|
|
e93bd14ef5 | ||
|
|
652f9f9eda | ||
|
|
cac9eb0cd7 | ||
|
|
3b4fb295ea | ||
|
|
a1ae61b5b1 | ||
|
|
355abd8c57 | ||
|
|
b57ac66815 | ||
|
|
a851a928d2 | ||
|
|
16c2e8e454 | ||
|
|
ae908c8e9b | ||
|
|
723c81470a | ||
|
|
a7905fba3e | ||
|
|
6e52b72523 | ||
|
|
ef4ec4185a |
@@ -19,18 +19,18 @@ jobs:
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
python-version: '3.x'
|
||||
# - name: Cache PlatformIO
|
||||
# uses: actions/cache@v3
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
# - name: Install PlatformIO
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip
|
||||
# pip install --upgrade platformio
|
||||
- name: Deploy updated JSON
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
@@ -43,5 +43,5 @@ jobs:
|
||||
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
||||
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
||||
# Upload to Platform.IO
|
||||
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
pio package publish rp2040-$TAG.zip --non-interactive
|
||||
# curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
# pio package publish rp2040-$TAG.zip --non-interactive
|
||||
|
||||
+12
-1
@@ -28,7 +28,7 @@
|
||||
#include "api/ArduinoAPI.h"
|
||||
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
||||
#include <pins_arduino.h>
|
||||
#include "hardware/gpio.h" // Required for the port*Register macros
|
||||
#include <hardware/gpio.h> // Required for the port*Register macros
|
||||
#include "debug_internal.h"
|
||||
#include <RP2040.h> // CMSIS
|
||||
|
||||
@@ -129,3 +129,14 @@ constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Warn users trying to use Pico SDK's STDIO implementation
|
||||
#include <pico/stdio.h> // Ensure it won't be re-included elsewhere
|
||||
#undef stdio_uart_init
|
||||
#define stdio_uart_init(...) static_assert(0, "stdio_uart_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
#undef stdio_init_all
|
||||
#define stdio_init_all(...) static_assert(0, "stdio_init_all is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
#undef stdio_usb_init
|
||||
#define stdio_usb_init(...) static_assert(0, "stdio_usb_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <hardware/structs/ioqspi.h>
|
||||
#include <hardware/structs/sio.h>
|
||||
|
||||
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
||||
//
|
||||
|
||||
@@ -28,14 +28,18 @@ CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
|
||||
_mutex = mutex;
|
||||
_acquired = false;
|
||||
_option = option;
|
||||
_pxHigherPriorityTaskWoken = 0; // pdFALSE
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_take_from_isr(m);
|
||||
} else {
|
||||
if (!__freertos_mutex_try_take(m)) {
|
||||
|
||||
if (__freertos_check_if_in_isr()) {
|
||||
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
|
||||
return;
|
||||
}
|
||||
// At this point we have the mutex in ISR
|
||||
} else {
|
||||
// Grab the mutex normally, possibly waking other tasks to get it
|
||||
__freertos_mutex_take(m);
|
||||
}
|
||||
} else {
|
||||
uint32_t owner;
|
||||
@@ -56,8 +60,8 @@ CoreMutex::~CoreMutex() {
|
||||
if (_acquired) {
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_give_from_isr(m);
|
||||
if (__freertos_check_if_in_isr()) {
|
||||
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
|
||||
} else {
|
||||
__freertos_mutex_give(m);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include "_freertos.h"
|
||||
|
||||
enum {
|
||||
DebugEnable = 1,
|
||||
FromISR = 1 << 1,
|
||||
DebugEnable = 1
|
||||
};
|
||||
|
||||
class CoreMutex {
|
||||
@@ -44,4 +43,5 @@ private:
|
||||
mutex_t *_mutex;
|
||||
bool _acquired;
|
||||
uint8_t _option;
|
||||
BaseType_t _pxHigherPriorityTaskWoken;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
RP2040 PIO utility class
|
||||
|
||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "PIOProgram.h"
|
||||
#include <map>
|
||||
|
||||
static std::map<const pio_program_t *, int> __pioMap[2];
|
||||
auto_init_mutex(_pioMutex);
|
||||
|
||||
|
||||
PIOProgram::PIOProgram(const pio_program_t *pgm) {
|
||||
_pgm = pgm;
|
||||
_pio = nullptr;
|
||||
_sm = -1;
|
||||
}
|
||||
|
||||
// We leave the INSN loaded in INSN RAM
|
||||
PIOProgram::~PIOProgram() {
|
||||
if (_pio) {
|
||||
pio_sm_unclaim(_pio, _sm);
|
||||
}
|
||||
}
|
||||
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset) {
|
||||
CoreMutex m(&_pioMutex);
|
||||
PIO pi[2] = { pio0, pio1 };
|
||||
|
||||
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
|
||||
for (int o = 0; o < 2; o++) {
|
||||
auto p = __pioMap[o].find(_pgm);
|
||||
if (p != __pioMap[o].end()) {
|
||||
int idx = pio_claim_unused_sm(pi[o], false);
|
||||
if (idx >= 0) {
|
||||
_pio = pi[o];
|
||||
_sm = idx;
|
||||
*pio = pi[o];
|
||||
*sm = idx;
|
||||
*offset = p->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not in any PIO IRAM, so try and add
|
||||
for (int o = 0; o < 2; o++) {
|
||||
if (pio_can_add_program(pi[o], _pgm)) {
|
||||
int idx = pio_claim_unused_sm(pi[o], false);
|
||||
if (idx >= 0) {
|
||||
int off = pio_add_program(pi[o], _pgm);
|
||||
__pioMap[o].insert({_pgm, off});
|
||||
_pio = pi[o];
|
||||
_sm = idx;
|
||||
*pio = pi[o];
|
||||
*sm = idx;
|
||||
*offset = off;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nope, no room either for SMs or INSNs
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
RP2040 PIO utility class
|
||||
|
||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hardware/pio.h>
|
||||
|
||||
// Wrapper class for PIO programs, abstracting common operations out
|
||||
class PIOProgram {
|
||||
public:
|
||||
PIOProgram(const pio_program_t *pgm);
|
||||
~PIOProgram();
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool prepare(PIO *pio, int *sm, int *offset);
|
||||
|
||||
private:
|
||||
const pio_program_t *_pgm;
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
};
|
||||
@@ -29,7 +29,9 @@
|
||||
#include <pico/multicore.h>
|
||||
#include <pico/rand.h>
|
||||
#include <pico/util/queue.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include "CoreMutex.h"
|
||||
#include "PIOProgram.h"
|
||||
#include "ccount.pio.h"
|
||||
#include <malloc.h>
|
||||
|
||||
@@ -91,15 +93,14 @@ public:
|
||||
if (!_multicore) {
|
||||
return;
|
||||
}
|
||||
__holdUpPendSV = 1;
|
||||
if (__isFreeRTOS) {
|
||||
vTaskPreemptionDisable(nullptr);
|
||||
vTaskSuspendAll();
|
||||
__freertos_idle_other_core();
|
||||
} else {
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
|
||||
void resumeOtherCore() {
|
||||
@@ -109,10 +110,8 @@ public:
|
||||
mutex_exit(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
if (__isFreeRTOS) {
|
||||
xTaskResumeAll();
|
||||
vTaskPreemptionEnable(nullptr);
|
||||
__freertos_resume_other_core();
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
|
||||
// Other core will exit busy-loop and return to operation
|
||||
// once __otherCoreIdled == false.
|
||||
@@ -156,65 +155,9 @@ private:
|
||||
class RP2040;
|
||||
extern RP2040 rp2040;
|
||||
extern "C" void main1();
|
||||
class PIOProgram;
|
||||
|
||||
extern "C" char __StackLimit;
|
||||
extern "C" char __bss_end__;
|
||||
|
||||
// Wrapper class for PIO programs, abstracting common operations out
|
||||
// TODO - Add unload/destructor
|
||||
class PIOProgram {
|
||||
public:
|
||||
PIOProgram(const pio_program_t *pgm) {
|
||||
_pgm = pgm;
|
||||
}
|
||||
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool prepare(PIO *pio, int *sm, int *offset) {
|
||||
extern mutex_t _pioMutex;
|
||||
CoreMutex m(&_pioMutex);
|
||||
// Is there an open slot to run in, first?
|
||||
if (!_findFreeSM(pio, sm)) {
|
||||
return false;
|
||||
}
|
||||
// Is it loaded on that PIO?
|
||||
if (_offset[pio_get_index(*pio)] < 0) {
|
||||
// Nope, need to load it
|
||||
if (!pio_can_add_program(*pio, _pgm)) {
|
||||
return false;
|
||||
}
|
||||
_offset[pio_get_index(*pio)] = pio_add_program(*pio, _pgm);
|
||||
}
|
||||
// Here it's guaranteed loaded, return values
|
||||
// PIO and SM already set
|
||||
*offset = _offset[pio_get_index(*pio)];
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Find an unused PIO state machine to grab, returns false when none available
|
||||
static bool _findFreeSM(PIO *pio, int *sm) {
|
||||
int idx = pio_claim_unused_sm(pio0, false);
|
||||
if (idx >= 0) {
|
||||
*pio = pio0;
|
||||
*sm = idx;
|
||||
return true;
|
||||
}
|
||||
idx = pio_claim_unused_sm(pio1, false);
|
||||
if (idx >= 0) {
|
||||
*pio = pio1;
|
||||
*sm = idx;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int _offset[2] = { -1, -1 };
|
||||
const pio_program_t *_pgm;
|
||||
};
|
||||
|
||||
class RP2040 {
|
||||
public:
|
||||
RP2040() { /* noop */ }
|
||||
@@ -320,6 +263,13 @@ public:
|
||||
reboot();
|
||||
}
|
||||
|
||||
inline void rebootToBootloader() {
|
||||
reset_usb_boot(0, 0);
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
static void enableDoubleResetBootloader();
|
||||
|
||||
void wdt_begin(uint32_t delay_ms) {
|
||||
|
||||
+63
-11
@@ -25,17 +25,16 @@
|
||||
#include "CoreMutex.h"
|
||||
#include "RP2040USB.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "class/midi/midi.h"
|
||||
#include "pico/time.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "pico/usb_reset_interface.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include <tusb.h>
|
||||
#include <class/hid/hid_device.h>
|
||||
#include <class/audio/audio.h>
|
||||
#include <pico/time.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <pico/usb_reset_interface.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include "sdkoverride/tusb_absmouse.h"
|
||||
#include <device/usbd_pvt.h>
|
||||
|
||||
@@ -550,6 +549,59 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
|
||||
*driver_count = 1;
|
||||
return &_resetd_driver;
|
||||
}
|
||||
|
||||
#elif defined NO_USB
|
||||
|
||||
// will ensure backward compatibility with existing code when using pico-debug
|
||||
|
||||
#warning "NO_USB selected. No output to Serial will occur!"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void SerialUSB::begin(unsigned long baud) {
|
||||
}
|
||||
|
||||
void SerialUSB::end() {
|
||||
|
||||
}
|
||||
|
||||
int SerialUSB::peek() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SerialUSB::read() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SerialUSB::available() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SerialUSB::availableForWrite() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SerialUSB::flush() {
|
||||
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(uint8_t c) {
|
||||
(void) c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
(void) buf;
|
||||
(void) length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SerialUSB::operator bool() {
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialUSB Serial;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
|
||||
// Weak function definitions for each type of endpoint
|
||||
extern void __USBInstallSerial() __attribute__((weak));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 3
|
||||
#define ARDUINO_PICO_MINOR 2
|
||||
#define ARDUINO_PICO_MINOR 3
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "3.2.0"
|
||||
#define ARDUINO_PICO_VERSION_STR "3.3.0"
|
||||
|
||||
+21
-14
@@ -46,22 +46,24 @@ static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
|
||||
return p;
|
||||
}
|
||||
|
||||
static PIOProgram *_getTxProgram(int bits) {
|
||||
auto f = _txMap.find(bits);
|
||||
static PIOProgram *_getTxProgram(int bits, bool inverted) {
|
||||
int key = inverted ? -bits : bits;
|
||||
auto f = _txMap.find(key);
|
||||
if (f == _txMap.end()) {
|
||||
pio_program_t * p = pio_make_uart_prog(bits, &pio_tx_program);
|
||||
_txMap.insert({bits, new PIOProgram(p)});
|
||||
f = _txMap.find(bits);
|
||||
pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_tx_inv_program : &pio_tx_program);
|
||||
_txMap.insert({key, new PIOProgram(p)});
|
||||
f = _txMap.find(key);
|
||||
}
|
||||
return f->second;
|
||||
}
|
||||
|
||||
static PIOProgram *_getRxProgram(int bits) {
|
||||
auto f = _rxMap.find(bits);
|
||||
static PIOProgram *_getRxProgram(int bits, bool inverted) {
|
||||
int key = inverted ? -bits : bits;
|
||||
auto f = _rxMap.find(key);
|
||||
if (f == _rxMap.end()) {
|
||||
pio_program_t * p = pio_make_uart_prog(bits, &pio_rx_program);
|
||||
_rxMap.insert({bits, new PIOProgram(p)});
|
||||
f = _rxMap.find(bits);
|
||||
pio_program_t * p = pio_make_uart_prog(bits, inverted ? &pio_rx_inv_program : &pio_rx_program);
|
||||
_rxMap.insert({key, new PIOProgram(p)});
|
||||
f = _rxMap.find(key);
|
||||
}
|
||||
return f->second;
|
||||
}
|
||||
@@ -96,7 +98,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||
return;
|
||||
}
|
||||
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
|
||||
uint32_t decode = _rxPIO->rxf[_rxSM];
|
||||
uint32_t decode = _rxPIO->rxf[_rxSM] ^ (_rxInverted ? 0xffffffff : 0);
|
||||
decode >>= 33 - _rxBits;
|
||||
uint32_t val = 0;
|
||||
for (int b = 0; b < _bits + 1; b++) {
|
||||
@@ -189,7 +191,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
|
||||
if (_tx != NOPIN) {
|
||||
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
||||
_txPgm = _getTxProgram(_txBits);
|
||||
_txPgm = _getTxProgram(_txBits, _txInverted);
|
||||
int off;
|
||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
||||
@@ -216,7 +218,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_reader = 0;
|
||||
|
||||
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
|
||||
_rxPgm = _getRxProgram(_rxBits);
|
||||
_rxPgm = _getRxProgram(_rxBits, _rxInverted);
|
||||
int off;
|
||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
||||
@@ -346,6 +348,11 @@ void SerialPIO::flush() {
|
||||
delay((1000 * (_txBits + 1)) / _baud);
|
||||
}
|
||||
|
||||
void SerialPIO::setInverted(bool invTx, bool invRx) {
|
||||
_txInverted = invTx;
|
||||
_rxInverted = invRx;
|
||||
}
|
||||
|
||||
size_t SerialPIO::write(uint8_t c) {
|
||||
CoreMutex m(&_mutex);
|
||||
if (!_running || !m || (_tx == NOPIN)) {
|
||||
@@ -364,7 +371,7 @@ size_t SerialPIO::write(uint8_t c) {
|
||||
}
|
||||
val <<= 1; // Start bit = low
|
||||
|
||||
pio_sm_put_blocking(_txPIO, _txSM, val);
|
||||
pio_sm_put_blocking(_txPIO, _txSM, _txInverted ? ~val : val);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
void begin(unsigned long baud, uint16_t config) override;
|
||||
void end() override;
|
||||
|
||||
void setInverted(bool invTx = true, bool invRx = true);
|
||||
|
||||
virtual int peek() override;
|
||||
virtual int read() override;
|
||||
virtual int available() override;
|
||||
@@ -63,6 +65,8 @@ protected:
|
||||
int _stop;
|
||||
bool _overflow;
|
||||
mutex_t _mutex;
|
||||
bool _txInverted = false;
|
||||
bool _rxInverted = false;
|
||||
|
||||
PIOProgram *_txPgm;
|
||||
PIO _txPIO;
|
||||
|
||||
+13
-12
@@ -25,15 +25,15 @@
|
||||
#include <Arduino.h>
|
||||
#include "CoreMutex.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "hardware/resets.h"
|
||||
#include <tusb.h>
|
||||
#include <pico/time.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <hardware/resets.h>
|
||||
|
||||
#ifndef DISABLE_USB_SERIAL
|
||||
// Ensure we are installed in the USB chain
|
||||
@@ -177,8 +177,10 @@ static bool _rts = false;
|
||||
static int _bps = 115200;
|
||||
static bool _rebooting = false;
|
||||
static void CheckSerialReset() {
|
||||
__holdUpPendSV = 1; // Ensure we don't get swapped out by FreeRTOS
|
||||
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
|
||||
if (__isFreeRTOS) {
|
||||
__freertos_idle_other_core();
|
||||
}
|
||||
_rebooting = true;
|
||||
// Disable NVIC IRQ, so that we don't get bothered anymore
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
@@ -186,11 +188,10 @@ static void CheckSerialReset() {
|
||||
reset_block(RESETS_RESET_USBCTRL_BITS);
|
||||
unreset_block(RESETS_RESET_USBCTRL_BITS);
|
||||
// Delay a bit, so the PC can figure out that we have disconnected.
|
||||
sleep_ms(3);
|
||||
busy_wait_ms(3);
|
||||
reset_usb_boot(0, 0);
|
||||
while (1); // WDT will fire here
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
}
|
||||
|
||||
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdint.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void randomSeed(uint32_t dwSeed) {
|
||||
if (dwSeed != 0) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "_freertos.h"
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include <stdlib.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
|
||||
// Cannot include refs to FreeRTOS's actual semaphore calls because they
|
||||
// are implemented as macros, so we have a wrapper in our variant hook
|
||||
@@ -35,32 +35,26 @@ extern "C" {
|
||||
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
||||
typedef struct QueueDefinition * QueueHandle_t;
|
||||
typedef QueueHandle_t SemaphoreHandle_t;
|
||||
typedef int32_t BaseType_t;
|
||||
#endif
|
||||
|
||||
extern bool __freertos_check_if_in_isr() __attribute__((weak));
|
||||
|
||||
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
|
||||
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
|
||||
|
||||
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
||||
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
||||
|
||||
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
extern void vTaskSuspendAll() __attribute__((weak));
|
||||
extern int32_t xTaskResumeAll() __attribute__((weak));
|
||||
|
||||
typedef struct tskTaskControlBlock * TaskHandle_t;
|
||||
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
|
||||
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
|
||||
#endif
|
||||
|
||||
extern void __freertos_idle_other_core() __attribute__((weak));
|
||||
extern void __freertos_resume_other_core() __attribute__((weak));
|
||||
}
|
||||
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
|
||||
|
||||
// Halt the FreeRTOS PendSV task switching magic
|
||||
extern "C" int __holdUpPendSV;
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include <lwip/netif.h>
|
||||
extern "C" {
|
||||
#include "cyw43.h"
|
||||
#include "cyw43_stats.h"
|
||||
#include <cyw43.h>
|
||||
#include <cyw43_stats.h>
|
||||
}
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// From cyw43_ctrl.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
LWIP wrappers to protect against timer-based re-entrancy
|
||||
|
||||
Copyright (c) 202s Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
@@ -27,11 +27,8 @@
|
||||
RP2040 rp2040;
|
||||
extern "C" {
|
||||
volatile bool __otherCoreIdled = false;
|
||||
int __holdUpPendSV = 0;
|
||||
};
|
||||
|
||||
mutex_t _pioMutex;
|
||||
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
@@ -92,8 +89,6 @@ extern "C" int main() {
|
||||
_REENT_INIT_PTR(_impure_ptr1);
|
||||
}
|
||||
|
||||
mutex_init(&_pioMutex);
|
||||
|
||||
rp2040.begin();
|
||||
|
||||
initVariant();
|
||||
@@ -163,6 +158,7 @@ extern "C" void __register_impure_ptr(struct _reent *p) {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" struct _reent *__wrap___getreent() __attribute__((weak));
|
||||
extern "C" struct _reent *__wrap___getreent() {
|
||||
if (get_core_num() == 0) {
|
||||
return _impure_ptr;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
; We shift out the start and stop bit as part of the FIFO
|
||||
set x, 9
|
||||
|
||||
pull side 1 ; Force stop bit
|
||||
pull side 1 ; Force stop bit high
|
||||
|
||||
; Send the bits
|
||||
bitloop:
|
||||
@@ -41,6 +41,26 @@ wait_bit:
|
||||
|
||||
|
||||
|
||||
; inverted-logic version (inverts the stop bit)
|
||||
|
||||
.program pio_tx_inv
|
||||
.side_set 1 opt
|
||||
|
||||
|
||||
; We shift out the start and stop bit as part of the FIFO
|
||||
set x, 9
|
||||
|
||||
pull side 0 ; Force stop bit low
|
||||
|
||||
; Send the bits
|
||||
bitloop:
|
||||
out pins, 1
|
||||
mov y, isr ; ISR is loaded by the setup routine with the period-1 count
|
||||
wait_bit:
|
||||
jmp y-- wait_bit
|
||||
jmp x-- bitloop
|
||||
|
||||
|
||||
% c-sdk {
|
||||
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
@@ -68,7 +88,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
|
||||
|
||||
.program pio_rx
|
||||
|
||||
@@ -91,6 +111,27 @@ wait_half:
|
||||
push ; Stuff it and wait for next start
|
||||
|
||||
|
||||
.program pio_rx_inv
|
||||
|
||||
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
|
||||
|
||||
start:
|
||||
set x, 18 ; Preload bit counter...we'll shift in the start bit and stop bit, and each bit will be double-recorded (to be fixed by RP2040 code)
|
||||
wait 1 pin 0 ; Stall until start bit is asserted
|
||||
|
||||
bitloop:
|
||||
; Delay until 1/2 way into the bit time
|
||||
mov y, osr
|
||||
wait_half:
|
||||
jmp y-- wait_half
|
||||
|
||||
; Read in the bit
|
||||
in pins, 1 ; Shift data bit into ISR
|
||||
jmp x-- bitloop ; Loop all bits
|
||||
|
||||
push ; Stuff it and wait for next start
|
||||
|
||||
|
||||
% c-sdk {
|
||||
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
@@ -37,6 +39,39 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------- //
|
||||
// pio_tx_inv //
|
||||
// ---------- //
|
||||
|
||||
#define pio_tx_inv_wrap_target 0
|
||||
#define pio_tx_inv_wrap 5
|
||||
|
||||
static const uint16_t pio_tx_inv_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0xe029, // 0: set x, 9
|
||||
0x90a0, // 1: pull block side 0
|
||||
0x6001, // 2: out pins, 1
|
||||
0xa046, // 3: mov y, isr
|
||||
0x0084, // 4: jmp y--, 4
|
||||
0x0042, // 5: jmp x--, 2
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program pio_tx_inv_program = {
|
||||
.instructions = pio_tx_inv_program_instructions,
|
||||
.length = 6,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_tx_inv_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + pio_tx_inv_wrap_target, offset + pio_tx_inv_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
@@ -90,6 +125,39 @@ static inline pio_sm_config pio_rx_program_get_default_config(uint offset) {
|
||||
sm_config_set_wrap(&c, offset + pio_rx_wrap_target, offset + pio_rx_wrap);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------- //
|
||||
// pio_rx_inv //
|
||||
// ---------- //
|
||||
|
||||
#define pio_rx_inv_wrap_target 0
|
||||
#define pio_rx_inv_wrap 6
|
||||
|
||||
static const uint16_t pio_rx_inv_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0xe032, // 0: set x, 18
|
||||
0x20a0, // 1: wait 1 pin, 0
|
||||
0xa047, // 2: mov y, osr
|
||||
0x0083, // 3: jmp y--, 3
|
||||
0x4001, // 4: in pins, 1
|
||||
0x0042, // 5: jmp x--, 2
|
||||
0x8020, // 6: push block
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program pio_rx_inv_program = {
|
||||
.instructions = pio_rx_inv_program_instructions,
|
||||
.length = 7,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_rx_inv_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + pio_rx_inv_wrap_target, offset + pio_rx_inv_wrap);
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include <pico/time.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
|
||||
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
|
||||
|
||||
@@ -77,7 +77,7 @@ static std::map<pin_size_t, CBInfo> _map;
|
||||
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
|
||||
(void) events;
|
||||
// Only need to lock around the std::map check, not the whole IRQ callback
|
||||
CoreMutex m(&_irqMutex, (FromISR | DebugEnable));
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ need to be periodically sampled to be read by applications, easily, such as:
|
||||
* Light dependent resistors (LDR), etc.
|
||||
|
||||
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A4``), and all
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A3``), and all
|
||||
recording is done at 16-bit levels (but be aware that the ADC in the Pico will only
|
||||
ever return values between 0...4095).
|
||||
|
||||
@@ -29,7 +29,7 @@ ADC Input API
|
||||
ADCInput(pin0 [, pin1, pin2, pin3])
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Creates an ADC input object which will record the pins specified in the code.
|
||||
Only pins ``A0`` ... ``A4`` can be used, and they must be specified in increasing
|
||||
Only pins ``A0`` ... ``A3`` can be used, and they must be specified in increasing
|
||||
order (i.e. ``ADCInput(A0, A1);`` is valid, but ``ADCInput(A1, A0)`` is not.
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords)
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'3.2.0'
|
||||
version = u'3.3.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'3.2.0'
|
||||
release = u'3.3.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+3
-2
@@ -10,7 +10,8 @@ Contributing to the Core (Pull Requests)
|
||||
----------------------------------------
|
||||
|
||||
We use the standard GitHub Pull Request model. If you're unfamiliar with it,
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>` gives a simple overview of the process.
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>`__
|
||||
gives a simple overview of the process.
|
||||
|
||||
All pull requests have to pass a set of Continuous Integration (CI) checks
|
||||
which help make sure the code compiles under different configurations and has
|
||||
@@ -84,7 +85,7 @@ code that only runs on this core, use the following define.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
#if defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__)
|
||||
~~~ your changes ~~~
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
HTTPClient Library
|
||||
==================
|
||||
|
||||
A simple HTTP requestor that can handle both HTTP and HTTP requests is
|
||||
A simple HTTP requester that can handle both HTTP and HTTPS requests is
|
||||
included as the ``HTTPClient`` library.
|
||||
|
||||
Check the examples for use under HTTP and HTTPS configurations. In general,
|
||||
|
||||
+6
-1
@@ -84,6 +84,11 @@ void flush()
|
||||
~~~~~~~~~~~~
|
||||
Waits until all the I2S buffers have been output.
|
||||
|
||||
void getOverUnderflow()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns a flag indicating if the I2S system ran our of data to send on output,
|
||||
or had to throw away data on input.
|
||||
|
||||
size_t write(uint8_t/int8_t/int16_t/int32_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
|
||||
@@ -112,7 +117,7 @@ many bytes were actually written.
|
||||
|
||||
int availableForWrite()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the number of L/R samples that can be written without
|
||||
Returns the amount of bytes that can be written without
|
||||
potentially blocking.
|
||||
|
||||
int read()
|
||||
|
||||
@@ -38,6 +38,22 @@ prevent the Arduino IDE from accessing. For Arduino IDE V2, override the filesys
|
||||
restriction using ``flatpak override --user --filesystem=host cc.arduino.IDE2`` . For
|
||||
For Arduino IDE < V2, use ``flatpak override --user --filesystem=host cc.arduino.arduinoide``.
|
||||
|
||||
Installing via Arduino CLI
|
||||
--------------------------
|
||||
To install using the Arduino command line tool (arduino-cli):
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli config add board_manager.additional_urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install rp2040:rp2040
|
||||
|
||||
To list the supported boards:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli board listall | grep rp2040
|
||||
|
||||
Installing via GIT
|
||||
------------------
|
||||
To install via GIT (for latest and greatest versions):
|
||||
|
||||
@@ -95,3 +95,7 @@ void rp2040.enableDoubleResetBootloader()
|
||||
Add a call anywhere in the sketch to ``rp2040.enableDoubleResetBootloader()`` and
|
||||
the core will check for a double-tap on reset, and if found will start the USB
|
||||
bootloader.
|
||||
|
||||
void rp2040.rebootToBootloader()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Will reboot the RP2040 into USB UF2 upload mode.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define PICO_SDK_VERSION_MAJOR 1
|
||||
#define PICO_SDK_VERSION_MINOR 5
|
||||
#define PICO_SDK_VERSION_REVISION 0
|
||||
#define PICO_SDK_VERSION_STRING "1.5.0"
|
||||
#define PICO_SDK_VERSION_REVISION 1
|
||||
#define PICO_SDK_VERSION_STRING "1.5.1"
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -94,7 +94,9 @@ SECTIONS
|
||||
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
|
||||
* FLASH ... we will include any thing excluded here in .data below by default */
|
||||
*(.init)
|
||||
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
|
||||
/* Some of these excludes required for PicoDVI library, won't affect most code */
|
||||
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.c.obj *divider.S.obj *PicoDVI.cpp.o *dvi.c.o) .text*)
|
||||
|
||||
*(.fini)
|
||||
/* Pull all c'tors into .text */
|
||||
*crtbegin.o(.ctors)
|
||||
|
||||
@@ -79,6 +79,10 @@ void ADCInput::onReceive(void(*fn)(void)) {
|
||||
}
|
||||
|
||||
bool ADCInput::begin() {
|
||||
if (_running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_running = true;
|
||||
|
||||
_isHolding = 0;
|
||||
@@ -105,7 +109,11 @@ bool ADCInput::begin() {
|
||||
setFrequency(_freq);
|
||||
|
||||
_arb = new AudioBufferManager(_buffers, _bufferWords, 0, INPUT, DMA_SIZE_16);
|
||||
_arb->begin(DREQ_ADC, (volatile void*)&adc_hw->fifo);
|
||||
if (!_arb->begin(DREQ_ADC, (volatile void*)&adc_hw->fifo)) {
|
||||
delete _arb;
|
||||
_arb = nullptr;
|
||||
return false;
|
||||
}
|
||||
_arb->setCallback(_cb);
|
||||
|
||||
adc_fifo_drain();
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: a2bcb19f6c...b17ab37a0e
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
#include <hardware/dma.h>
|
||||
#include <hardware/irq.h>
|
||||
#include "AudioBufferManager.h"
|
||||
|
||||
static int __channelCount = 0; // # of channels left. When we hit 0, then remove our handler
|
||||
@@ -78,8 +78,8 @@ AudioBufferManager::~AudioBufferManager() {
|
||||
dma_channel_abort(_channelDMA[i]);
|
||||
dma_channel_unclaim(_channelDMA[i]);
|
||||
dma_channel_acknowledge_irq0(_channelDMA[i]);
|
||||
__channelCount--;
|
||||
}
|
||||
__channelCount--;
|
||||
if (!__channelCount) {
|
||||
irq_set_enabled(DMA_IRQ_0, false);
|
||||
// TODO - how can we know if there are no other parts of the core using DMA0 IRQ??
|
||||
@@ -114,7 +114,7 @@ bool AudioBufferManager::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
|
||||
// Get ping and pong DMA channels
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
_channelDMA[i] = dma_claim_unused_channel(true);
|
||||
_channelDMA[i] = dma_claim_unused_channel(false);
|
||||
if (_channelDMA[i] == -1) {
|
||||
if (i == 1) {
|
||||
dma_channel_unclaim(_channelDMA[0]);
|
||||
@@ -257,7 +257,7 @@ void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
|
||||
_active[1] = _takeFromList(&_filled);
|
||||
}
|
||||
_overunderflow = _overunderflow | (_active[1] == _silence);
|
||||
dma_channel_set_read_addr(channel, _active[0]->buff, false);
|
||||
dma_channel_set_read_addr(channel, _active[1]->buff, false);
|
||||
} else {
|
||||
if (_empty) {
|
||||
_addToList(&_filled, _active[0]);
|
||||
@@ -266,7 +266,7 @@ void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
|
||||
} else {
|
||||
_overunderflow = true;
|
||||
}
|
||||
dma_channel_set_write_addr(channel, _active[0]->buff, false);
|
||||
dma_channel_set_write_addr(channel, _active[1]->buff, false);
|
||||
}
|
||||
dma_channel_set_trans_count(channel, _wordsPerBuffer * (_dmaSize == DMA_SIZE_16 ? 2 : 1), false);
|
||||
dma_channel_acknowledge_irq0(channel);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include "hardware/dma.h"
|
||||
#include <hardware/dma.h>
|
||||
|
||||
class AudioBufferManager {
|
||||
public:
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <BTstackLib.h>
|
||||
#include <SPI.h>
|
||||
|
||||
/*
|
||||
EXAMPLE_START(LEDeviceScanner): LE Device Scanner
|
||||
|
||||
@text The LE Device Scanner monitors BLE device advertisements,
|
||||
keeping track of one or more known devices as they appear.
|
||||
*/
|
||||
|
||||
// Application state
|
||||
int counter[2] = {0, 0};
|
||||
BD_ADDR known_devices[2] = {BD_ADDR("DB:88:B6:70:9E:EB"),
|
||||
BD_ADDR("C9:60:BD:F2:B4:9D")
|
||||
};
|
||||
|
||||
/*
|
||||
@section Setup
|
||||
|
||||
@text After BTstack.setup(), BTstack is configured to call
|
||||
advertisementCallback whenever an Advertisement was received.
|
||||
*/
|
||||
/* LISTING_START(LEDeviceScannerSetup): LE Device Scanner Setup */
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
BTstack.setBLEAdvertisementCallback(advertisementCallback);
|
||||
BTstack.setup();
|
||||
BTstack.bleStartScanning();
|
||||
}
|
||||
/* LISTING_END(LEDeviceScannerSetup): LE Device Scanner Setup */
|
||||
|
||||
/*
|
||||
@section Loop
|
||||
|
||||
@text In the standard Arduino loop() function, BTstack's loop() is called.
|
||||
*/
|
||||
/* LISTING_START(LEDeviceScannerLoop): Loop */
|
||||
void loop(void) {
|
||||
BTstack.loop();
|
||||
}
|
||||
/* LISTING_END(LEDeviceScannerLoop): Loop */
|
||||
|
||||
/*
|
||||
@section Advertisement Callback
|
||||
|
||||
@text Whenever an Advertisement is received, isIBeacon() checks if
|
||||
it contains an iBeacon.
|
||||
|
||||
If it's not an iBeacon, the BD_ADDR is compared to the address we are
|
||||
looking for and the counter is incremented.
|
||||
*/
|
||||
/* LISTING_START(LEDeviceScannerAdvertisementCallback): Advertisement Callback
|
||||
*/
|
||||
void advertisementCallback(BLEAdvertisement *bleAdvertisement) {
|
||||
if (!(bleAdvertisement->isIBeacon())) {
|
||||
Serial.print("Device discovered: ");
|
||||
Serial.println(bleAdvertisement->getBdAddr()->getAddressString());
|
||||
for (size_t i = 0; i < sizeof(counter) / sizeof(int); i++) {
|
||||
if (memcmp(bleAdvertisement->getBdAddr()->getAddress(),
|
||||
known_devices[i].getAddress(), sizeof(known_devices[i])) == 0) {
|
||||
counter[i]++;
|
||||
Serial.printf("Known device: %s, has been discovered %d times.\n",
|
||||
known_devices[i].getAddressString(), counter[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* LISTING_END(LEDeviceScannerAdvertisementCallback): Advertisement Callback */
|
||||
@@ -396,9 +396,13 @@ BD_ADDR::BD_ADDR(void) {
|
||||
}
|
||||
|
||||
BD_ADDR::BD_ADDR(const char * address_string, BD_ADDR_TYPE address_type) : address_type(address_type) {
|
||||
(void) address_string;
|
||||
// TODO: implement
|
||||
// log_error("BD_ADDR::BD_ADDR(const char *, BD_ADDR_TYPE) not implemented yet!");
|
||||
int processed = sscanf(address_string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", address, address + 1,
|
||||
address + 2, address + 3, address + 4, address + 5);
|
||||
if (processed != 6) { // Set address to zeroes if we did not get six bytes back.
|
||||
for (int i = 0; i < 6; i++) {
|
||||
address[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BD_ADDR::BD_ADDR(const uint8_t address[6], BD_ADDR_TYPE address_type) : address_type(address_type) {
|
||||
@@ -774,6 +778,10 @@ static hci_transport_config_uart_t config = {
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
void BTstackManager::setup(void) {
|
||||
setup("BTstack LE Shield");
|
||||
}
|
||||
|
||||
void BTstackManager::setup(const char * name) {
|
||||
|
||||
//#ifdef PIN_LED
|
||||
// pinMode(PIN_LED, OUTPUT);
|
||||
@@ -822,7 +830,6 @@ void BTstackManager::setup(void) {
|
||||
const uint8_t flags[] = { 0x02, 0x01, 0x02 };
|
||||
memcpy(&adv_data[pos], flags, sizeof(flags));
|
||||
pos += sizeof(flags);
|
||||
const char * name = "BTstack LE Shield";
|
||||
adv_data[pos++] = strlen(name) + 1;
|
||||
adv_data[pos++] = 0x09;
|
||||
memcpy(&adv_data[pos], name, strlen(name));
|
||||
|
||||
@@ -135,6 +135,7 @@ extern "C" {
|
||||
public:
|
||||
BTstackManager(void);
|
||||
void setup(void);
|
||||
void setup(const char * name);
|
||||
void loop(void);
|
||||
|
||||
void setPublicBdAddr(bd_addr_t addr);
|
||||
|
||||
@@ -36,6 +36,7 @@ pcTaskGetName KEYWORD2
|
||||
ulTaskNotifyTake KEYWORD2
|
||||
vTaskNotifyGiveFromISR KEYWORD2
|
||||
taskYIELD KEYWORD2
|
||||
vTaskCoreAffinitySet KEYWORD2
|
||||
vTaskSuspend KEYWORD2
|
||||
vTaskResume KEYWORD2
|
||||
xTaskResumeFromISR KEYWORD2
|
||||
@@ -43,6 +44,7 @@ xTaskGetTickCount KEYWORD2
|
||||
xTaskGetTickCountFromISR KEYWORD2
|
||||
uxTaskGetNumberOfTasks KEYWORD2
|
||||
uxTaskGetStackHighWaterMark KEYWORD2
|
||||
uxTaskGetSystemState KEYWORD2
|
||||
|
||||
# Instances (KEYWORD2)
|
||||
|
||||
|
||||
Submodule libraries/FreeRTOS/lib/FreeRTOS-Kernel updated: b5942ddd07...29fdcf092a
@@ -29,10 +29,7 @@
|
||||
#define configUSE_TASK_PREEMPTION_DISABLE 1
|
||||
|
||||
#define configUSE_NEWLIB_REENTRANT 1
|
||||
#define configNEWLIB_REENTRANT_IS_DYNAMIC 0 /* Note that we have a different config option, portSET_IMPURE_PTR */
|
||||
#include <reent.h>
|
||||
extern void __register_impure_ptr(struct _reent *p);
|
||||
#define portSET_IMPURE_PTR(x) __register_impure_ptr(x)
|
||||
#define configNEWLIB_REENTRANT_IS_DYNAMIC 1
|
||||
|
||||
/* Run time stats related definitions. */
|
||||
void vMainConfigureTimerForRunTimeStats(void);
|
||||
|
||||
@@ -1 +1,14 @@
|
||||
#include "../lib/FreeRTOS-Kernel/tasks.c"
|
||||
|
||||
//See https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/496
|
||||
struct _reent* __wrap___getreent(void) {
|
||||
// No lock needed because if this changes, we won't be running anymore.
|
||||
TCB_t *pxCurTask = xTaskGetCurrentTaskHandle();
|
||||
if (pxCurTask == NULL) {
|
||||
// No task running. Return global struct.
|
||||
return _GLOBAL_REENT;
|
||||
} else {
|
||||
// We have a task; return its reentrant struct.
|
||||
return &pxCurTask->xNewLib_reent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,59 @@
|
||||
#include <pico.h>
|
||||
#include <pico/time.h>
|
||||
|
||||
#include "_freertos.h"
|
||||
#include <_freertos.h>
|
||||
|
||||
// Interfaces for the main core to use FreeRTOS mutexes
|
||||
extern "C" {
|
||||
extern volatile bool __otherCoreIdled;
|
||||
|
||||
SemaphoreHandle_t __freertos_mutex_create() {
|
||||
return xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
SemaphoreHandle_t _freertos_recursive_mutex_create() {
|
||||
return xSemaphoreCreateRecursiveMutex();
|
||||
}
|
||||
|
||||
void __freertos_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTake(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) {
|
||||
return xSemaphoreTakeFromISR(mtx, pxHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTake(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGive(mtx);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) {
|
||||
BaseType_t hiPrio = pxHigherPriorityTaskWoken ? *pxHigherPriorityTaskWoken : pdFALSE;
|
||||
xSemaphoreGiveFromISR(mtx, &hiPrio);
|
||||
portYIELD_FROM_ISR(hiPrio);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTakeRecursive(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGiveRecursive(mtx);
|
||||
}
|
||||
|
||||
bool __freertos_check_if_in_isr() {
|
||||
return portCHECK_IF_IN_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
@@ -108,6 +160,40 @@ extern "C" void yield() {
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
static TaskHandle_t __idleCoreTask[2];
|
||||
static void __no_inline_not_in_flash_func(IdleThisCore)(void *param) {
|
||||
(void) param;
|
||||
while (true) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
vTaskPreemptionDisable(nullptr);
|
||||
portDISABLE_INTERRUPTS();
|
||||
__otherCoreIdled = true;
|
||||
while (__otherCoreIdled) {
|
||||
/* noop */
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
vTaskPreemptionEnable(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void __no_inline_not_in_flash_func(__freertos_idle_other_core)() {
|
||||
vTaskPreemptionDisable(nullptr);
|
||||
xTaskNotifyGive(__idleCoreTask[ 1 ^ sio_hw->cpuid ]);
|
||||
while (!__otherCoreIdled) {
|
||||
/* noop */
|
||||
}
|
||||
portDISABLE_INTERRUPTS();
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
extern "C" void __no_inline_not_in_flash_func(__freertos_resume_other_core)() {
|
||||
__otherCoreIdled = false;
|
||||
portENABLE_INTERRUPTS();
|
||||
xTaskResumeAll();
|
||||
vTaskPreemptionEnable(nullptr);
|
||||
}
|
||||
|
||||
|
||||
extern mutex_t __usb_mutex;
|
||||
static TaskHandle_t __usbTask;
|
||||
static void __usb(void *param);
|
||||
@@ -124,6 +210,12 @@ void startFreeRTOS(void) {
|
||||
vTaskCoreAffinitySet(c1, 1 << 1);
|
||||
}
|
||||
|
||||
// Create the idle-other-core tasks (for when flash is being written)
|
||||
xTaskCreate(IdleThisCore, "IdleCore0", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 0);
|
||||
vTaskCoreAffinitySet(__idleCoreTask[0], 1 << 0);
|
||||
xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1);
|
||||
vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1);
|
||||
|
||||
// Initialise and run the freeRTOS scheduler. Execution should never return here.
|
||||
__freeRTOSinitted = true;
|
||||
vTaskStartScheduler();
|
||||
@@ -398,54 +490,7 @@ void __USBStart() {
|
||||
__SetupDescHIDReport();
|
||||
__SetupUSBDescriptor();
|
||||
|
||||
// Make highest prio and locked to core 0
|
||||
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
|
||||
// Make high prio and locked to core 0
|
||||
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 2, &__usbTask);
|
||||
vTaskCoreAffinitySet(__usbTask, 1 << 0);
|
||||
}
|
||||
|
||||
|
||||
// Interfaces for the main core to use FreeRTOS mutexes
|
||||
extern "C" {
|
||||
|
||||
SemaphoreHandle_t __freertos_mutex_create() {
|
||||
return xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
SemaphoreHandle_t _freertos_recursive_mutex_create() {
|
||||
return xSemaphoreCreateRecursiveMutex();
|
||||
}
|
||||
|
||||
void __freertos_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTake(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeFromISR(mtx, NULL);
|
||||
}
|
||||
|
||||
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTake(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGive(mtx);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGiveFromISR(mtx, NULL);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTakeRecursive(mtx, 0);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGiveRecursive(mtx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+35
-12
@@ -48,7 +48,7 @@ I2S::I2S(PinMode direction) {
|
||||
_freq = 48000;
|
||||
_arb = nullptr;
|
||||
_cb = nullptr;
|
||||
_buffers = 8;
|
||||
_buffers = 6;
|
||||
_bufferWords = 0;
|
||||
_silenceSample = 0;
|
||||
_isLSBJ = false;
|
||||
@@ -56,6 +56,7 @@ I2S::I2S(PinMode direction) {
|
||||
}
|
||||
|
||||
I2S::~I2S() {
|
||||
end();
|
||||
}
|
||||
|
||||
bool I2S::setBCLK(pin_size_t pin) {
|
||||
@@ -138,13 +139,19 @@ void I2S::onReceive(void(*fn)(void)) {
|
||||
bool I2S::begin() {
|
||||
_running = true;
|
||||
_hasPeeked = false;
|
||||
_isHolding = 0;
|
||||
int off = 0;
|
||||
if (!_swapClocks) {
|
||||
_i2s = new PIOProgram(_isOutput ? (_isLSBJ ? &pio_lsbj_out_program : &pio_i2s_out_program) : &pio_i2s_in_program);
|
||||
} else {
|
||||
_i2s = new PIOProgram(_isOutput ? (_isLSBJ ? &pio_lsbj_out_swap_program : &pio_i2s_out_swap_program) : &pio_i2s_in_swap_program);
|
||||
}
|
||||
_i2s->prepare(&_pio, &_sm, &off);
|
||||
if (!_i2s->prepare(&_pio, &_sm, &off)) {
|
||||
_running = false;
|
||||
delete _i2s;
|
||||
_i2s = nullptr;
|
||||
return false;
|
||||
}
|
||||
if (_isOutput) {
|
||||
if (_isLSBJ) {
|
||||
pio_lsbj_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps, _swapClocks);
|
||||
@@ -163,10 +170,17 @@ bool I2S::begin() {
|
||||
_silenceSample = (a << 16) | a;
|
||||
}
|
||||
if (!_bufferWords) {
|
||||
_bufferWords = 16 * (_bps == 32 ? 2 : 1);
|
||||
_bufferWords = 64 * (_bps == 32 ? 2 : 1);
|
||||
}
|
||||
_arb = new AudioBufferManager(_buffers, _bufferWords, _silenceSample, _isOutput ? OUTPUT : INPUT);
|
||||
_arb->begin(pio_get_dreq(_pio, _sm, _isOutput), _isOutput ? &_pio->txf[_sm] : (volatile void*)&_pio->rxf[_sm]);
|
||||
if (!_arb->begin(pio_get_dreq(_pio, _sm, _isOutput), _isOutput ? &_pio->txf[_sm] : (volatile void*)&_pio->rxf[_sm])) {
|
||||
_running = false;
|
||||
delete _arb;
|
||||
_arb = nullptr;
|
||||
delete _i2s;
|
||||
_i2s = nullptr;
|
||||
return false;
|
||||
}
|
||||
_arb->setCallback(_cb);
|
||||
pio_sm_set_enabled(_pio, _sm, true);
|
||||
|
||||
@@ -187,10 +201,18 @@ void I2S::end() {
|
||||
int I2S::available() {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
} else if (_isOutput) {
|
||||
return availableForWrite(); // Do what I mean, not what I say
|
||||
} else {
|
||||
return _arb->available();
|
||||
auto avail = _arb->available();
|
||||
avail *= 4; // 4 samples per 32-bits
|
||||
if (_bps < 24) {
|
||||
if (_isOutput) {
|
||||
// 16- and 8-bit can have holding bytes available
|
||||
avail += (32 - _isHolding) / 8;
|
||||
} else {
|
||||
avail += _isHolding / 8;
|
||||
}
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +241,7 @@ int I2S::read() {
|
||||
case 16:
|
||||
ret = _holdWord >> 16;
|
||||
_holdWord <<= 16;
|
||||
_isHolding -= 32;
|
||||
_isHolding -= 16;
|
||||
return ret;
|
||||
case 24:
|
||||
case 32:
|
||||
@@ -376,13 +398,14 @@ bool I2S::read32(int32_t *l, int32_t *r) {
|
||||
|
||||
size_t I2S::write(const uint8_t *buffer, size_t size) {
|
||||
// We can only write 32-bit chunks here
|
||||
if (size & 0x3) {
|
||||
if (size & 0x3 || !_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t writtenSize = 0;
|
||||
int32_t *p = (int32_t *)buffer;
|
||||
uint32_t *p = (uint32_t *)buffer;
|
||||
while (size) {
|
||||
if (!write((int32_t)*p)) {
|
||||
if (!_arb->write(*p, false)) {
|
||||
// Blocked, stop write here
|
||||
return writtenSize;
|
||||
} else {
|
||||
@@ -398,5 +421,5 @@ int I2S::availableForWrite() {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
return _arb->available();
|
||||
return available();
|
||||
}
|
||||
|
||||
@@ -54,6 +54,15 @@ public:
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) override;
|
||||
virtual int availableForWrite() override;
|
||||
|
||||
// From the AR
|
||||
bool getOverUnderflow() {
|
||||
if (!_running) {
|
||||
return false;
|
||||
} else {
|
||||
return _arb->getOverUnderflow();
|
||||
}
|
||||
}
|
||||
|
||||
// Try and make I2S::write() do what makes sense, namely write
|
||||
// one sample (L or R) at the I2S configured bit width
|
||||
virtual size_t write(uint8_t s) override {
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include "OpenPDMFilter.h"
|
||||
|
||||
extern "C" {
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include <hardware/pio.h>
|
||||
#include <hardware/dma.h>
|
||||
#include <hardware/clocks.h>
|
||||
}
|
||||
#include "hardware/sync.h"
|
||||
#include <hardware/sync.h>
|
||||
#include "pdm.pio.h"
|
||||
static PIOProgram _pdmPgm(&pdm_pio_program);
|
||||
|
||||
|
||||
@@ -100,6 +100,10 @@ void PWMAudio::onTransmit(void(*fn)(void)) {
|
||||
}
|
||||
|
||||
bool PWMAudio::begin() {
|
||||
if (_running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_stereo && (_pin & 1)) {
|
||||
// Illegal, need to have consecutive pins on the same PWM slice
|
||||
Serial.printf("ERROR: PWMAudio stereo mode requires pin be even\n");
|
||||
@@ -118,7 +122,13 @@ bool PWMAudio::begin() {
|
||||
uint32_t ccAddr = PWM_BASE + PWM_CH0_CC_OFFSET + pwm_gpio_to_slice_num(_pin) * 20;
|
||||
|
||||
_arb = new AudioBufferManager(_buffers, _bufferWords, 0x80008000, OUTPUT, DMA_SIZE_32);
|
||||
_arb->begin(pwm_get_dreq(pwm_gpio_to_slice_num(_pin)), (volatile void*)ccAddr);
|
||||
if (!_arb->begin(pwm_get_dreq(pwm_gpio_to_slice_num(_pin)), (volatile void*)ccAddr)) {
|
||||
_running = false;
|
||||
delete _arb;
|
||||
_arb = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
_arb->setCallback(_cb);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
// 3. Open up COMX: in your favorite terminal application and type away
|
||||
|
||||
// Under Mac to connect to the PicoW
|
||||
// 1. Sorry, you're on your own. If you have a Mac and can update this demo with a Pull Request it would be appreciated!
|
||||
// 1. Open System Preferences and go in the bluetooth section. You should find a bluetooth device called
|
||||
// PicoW Serial XX:XX:... Click Connect button.
|
||||
// 2. A /dev/tty.PicoWSerialXXXX becomes available.
|
||||
// 3. Connect to this device with your favorite terminal application.
|
||||
|
||||
|
||||
#include <SerialBT.h>
|
||||
|
||||
@@ -237,73 +237,6 @@ void HTTPServer::serveStatic(const char* uri, FS& fs, const char* path, const ch
|
||||
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
|
||||
}
|
||||
|
||||
void HTTPServer::httpHandleClient() {
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (_currentClient->connected()) {
|
||||
switch (_currentStatus) {
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClient->available()) {
|
||||
switch (_parseRequest(_currentClient)) {
|
||||
case CLIENT_REQUEST_CAN_CONTINUE:
|
||||
// Because HTTP_MAX_SEND_WAIT is expressed in milliseconds, it must be divided by 1000
|
||||
_currentClient->setTimeout(HTTP_MAX_SEND_WAIT / 1000);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
/* fallthrough */
|
||||
case CLIENT_REQUEST_IS_HANDLED:
|
||||
if (_currentClient->connected() || _currentClient->available()) {
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
} else {
|
||||
log_v("webserver: peer has closed after served\n");
|
||||
}
|
||||
break;
|
||||
case CLIENT_MUST_STOP:
|
||||
log_v("Close client\n");
|
||||
_currentClient->stop();
|
||||
break;
|
||||
case CLIENT_IS_GIVEN:
|
||||
// client must not be stopped but must not be handled here anymore
|
||||
// (example: tcp connection given to websocket)
|
||||
log_v("Give client\n");
|
||||
break;
|
||||
} // switch _parseRequest()
|
||||
} else { // !_currentClient->available()
|
||||
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient) {
|
||||
if (_currentClient) {
|
||||
delete _currentClient;
|
||||
_currentClient = nullptr;
|
||||
}
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
|
||||
if (callYield) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::httpClose() {
|
||||
_currentStatus = HC_NONE;
|
||||
|
||||
@@ -41,6 +41,7 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
|
||||
#endif
|
||||
|
||||
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
|
||||
#define HTTP_MAX_DATA_AVAILABLE_WAIT 30 //ms to wait for the client to send the request when there is another client with data available
|
||||
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
|
||||
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
|
||||
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
|
||||
@@ -74,7 +75,6 @@ public:
|
||||
virtual ~HTTPServer();
|
||||
|
||||
virtual void httpClose();
|
||||
virtual void httpHandleClient();
|
||||
|
||||
bool authenticate(const char * username, const char * password);
|
||||
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = nullptr, const String& authFailMsg = String(""));
|
||||
|
||||
@@ -90,19 +90,93 @@ void WebServerTemplate<ServerType, DefaultPort>::handleClient() {
|
||||
_currentClient = nullptr;
|
||||
}
|
||||
|
||||
ClientType client = _server.available();
|
||||
if (!client) {
|
||||
_currentClient = new ClientType(_server.available());
|
||||
if (!_currentClient) {
|
||||
if (_nullDelay) {
|
||||
delay(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_currentClient = new ClientType(client);
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
_statusChange = millis();
|
||||
}
|
||||
httpHandleClient();
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (_currentClient->connected()) {
|
||||
switch (_currentStatus) {
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClient->available()) {
|
||||
switch (_parseRequest(_currentClient)) {
|
||||
case CLIENT_REQUEST_CAN_CONTINUE:
|
||||
// Because HTTP_MAX_SEND_WAIT is expressed in milliseconds, it must be divided by 1000
|
||||
_currentClient->setTimeout(HTTP_MAX_SEND_WAIT / 1000);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
/* fallthrough */
|
||||
case CLIENT_REQUEST_IS_HANDLED:
|
||||
if (_currentClient->connected() || _currentClient->available()) {
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
} else {
|
||||
//log_v("webserver: peer has closed after served\n");
|
||||
}
|
||||
break;
|
||||
case CLIENT_MUST_STOP:
|
||||
//log_v("Close client\n");
|
||||
_currentClient->stop();
|
||||
break;
|
||||
case CLIENT_IS_GIVEN:
|
||||
// client must not be stopped but must not be handled here anymore
|
||||
// (example: tcp connection given to websocket)
|
||||
//log_v("Give client\n");
|
||||
break;
|
||||
} // switch _parseRequest()
|
||||
} else {
|
||||
// !_currentClient.available(): waiting for more data
|
||||
unsigned long timeSinceChange = millis() - _statusChange;
|
||||
// Use faster connection drop timeout if any other client has data
|
||||
// or the buffer of pending clients is full
|
||||
if ((_server.hasClientData() || _server.hasMaxPendingClients())
|
||||
&& timeSinceChange > HTTP_MAX_DATA_AVAILABLE_WAIT) {
|
||||
//log_v("webserver: closing since there's another connection to read from\r\n");
|
||||
} else {
|
||||
if (timeSinceChange > HTTP_MAX_DATA_WAIT) {
|
||||
//log_v("webserver: closing after read timeout\r\n");
|
||||
} else {
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient) {
|
||||
if (_currentClient) {
|
||||
delete _currentClient;
|
||||
_currentClient = nullptr;
|
||||
}
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
|
||||
if (callYield) {
|
||||
yield();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename ServerType, int DefaultPort>
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
|
||||
#include "CYW43shim.h"
|
||||
extern "C" {
|
||||
#include "cyw43.h"
|
||||
#include "cyw43_stats.h"
|
||||
#include <cyw43.h>
|
||||
#include <cyw43_stats.h>
|
||||
}
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// From cyw43_ctrl.c
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.30200.0",
|
||||
"version": "1.30300.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
+1
-1
Submodule pico-sdk updated: 2ccab115de...6a7db34ff6
+1
-1
@@ -20,7 +20,7 @@
|
||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||
|
||||
name=Raspberry Pi RP2040 Boards
|
||||
version=3.2.0
|
||||
version=3.3.0
|
||||
|
||||
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
|
||||
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
|
||||
|
||||
@@ -30,10 +30,12 @@
|
||||
#define PIN_SPI1_SS (31u)
|
||||
|
||||
// Wire
|
||||
#define PIN_WIRE0_SDA (24u)
|
||||
#define PIN_WIRE0_SCL (25u)
|
||||
#define PIN_WIRE1_SDA (2u)
|
||||
#define PIN_WIRE1_SCL (3u)
|
||||
#define __WIRE0_DEVICE i2c1
|
||||
#define PIN_WIRE0_SDA (2u)
|
||||
#define PIN_WIRE0_SCL (3u)
|
||||
#define __WIRE1_DEVICE i2c0
|
||||
#define PIN_WIRE1_SDA (24u)
|
||||
#define PIN_WIRE1_SCL (25u)
|
||||
|
||||
#define SERIAL_HOWMANY (2u)
|
||||
#define SPI_HOWMANY (1u)
|
||||
|
||||
Reference in New Issue
Block a user