Compare commits

..
16 Commits
Author SHA1 Message Date
Earle F. Philhower, III 7eb176c0b4 Update version 2023-06-07 18:06:55 -07:00
hreintke 3f475ac68c CoreMutex add portYieldFromISR for FreeRTOS (#1484) 2023-06-07 06:59:10 -07:00
Earle F. Philhower, III 5204dab99b Fix CoreMutex FreeRTOS ISR logic (#1510) 2023-06-07 00:15:41 -07:00
Earle F. Philhower, III 273fb84dc5 Update to Adafruit TinyUSB 2.2.1 (#1511)
Fixes #1509
2023-06-07 00:05:12 -07:00
LinusHeu fe3af4d98b Update i2s.rst + typo (#1504) 2023-06-05 13:10:04 -07:00
Earle F. Philhower, III 9aade5bb24 Update adc.rst (#1502) 2023-06-05 02:15:09 -07:00
Earle F. Philhower, III 3c408dab7c AudioBufferManager(I2s, PWMAudio, ADCInput) clicking fix (#1500)
The ABM had an off-by-one error in the DMA buffer swapover.  Instead of
setting the DMA address to the newly added buffer in active[], it set it
to the buffer that was currently running.

This would effectively disable the ping-pong and cause clicks/lost data.

Fixes #1491
2023-06-04 18:40:29 -07:00
Earle F. Philhower, III 2888f4d03d I2S::available/availableForWrite() returns bytes (#1499)
Per the Arduino documentation, I2s::available should return bytes free,
not samples.  Adjust accordingly.
2023-06-04 16:38:12 -07:00
Earle F. Philhower, III f57b5bc762 Add I2S::getOverUnderflow() (#1497)
See #1491.  Thanks @LinusHeu
2023-06-04 14:21:02 -07:00
Earle F. Philhower, III 35a4d57360 Fix I2s::available/availableForWrite() (#1496)
Return the actual number of samples that can be read/written, not the
number of 32-bit values there is space for.
2023-06-04 14:10:53 -07:00
Earle F. Philhower, III 579e366bcf Fix serial reset hang under FreeRTOS (#1495)
The serial port reset logic was calling `sleep_ms()` which ended up doing
a task switch...while the other core was frozen and everything was supposed
to be locked.

Use `busy_wait_ms()` which is a tight loop to delay in the reset portion.

Fixes #1486
2023-06-04 13:28:11 -07:00
hreintke db4f79448d CoreMutex freeRTOS Mutex acquire properly (#1481)
Since FreeRTOS has real tasks and mutexes with support for priority bumping, actually always try and take a `CoreMutex` instead of seeing if someone else already has it and aborting immediately.

This fix helps ensure things like Serial output in a multi-task system won't get lost.
2023-06-04 13:12:30 -07:00
LinusHeu 45bbcca207 AudioBufferManager: Make dma_claim_unused_channel() not panic (#1487) 2023-05-30 15:51:07 -07:00
Dominic PearmanandDominic Pearman 8e961a5667 Added setup overload to pass name. (#1483)
Co-authored-by: Dominic Pearman <dominic@phymorous.de>
2023-05-27 10:40:24 -07:00
Ivan Kravets 64ad69c247 Temporary disable publishing to the PIO registry (#1476)
See RPI's CEO comment https://github.com/platformio/platform-raspberrypi/pull/36#issuecomment-1560504425
2023-05-26 10:24:28 -07:00
Jan 4def2f219c Implement the BD_ADDR(char * address_string) constructor. (#1440)
* Implement the BD_ADDR(char * address_string) constructor.

* Updating implementation to use sscanf.

There is an extra step after the sscanf that checks that we got
six bytes back and if we did not, it will set all bytes in the
address to zero.

* Example using BD_ADDR(const char * address_string)

This example shows how BD_ADDR(const char * address_string) can
be used to create BD_ADDR objects to use for comparisons etc.

* Update LEDeviceScanner.ino formatting
2023-05-25 06:54:24 -07:00
20 changed files with 156 additions and 48 deletions
+12 -12
View File
@@ -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
+8 -4
View File
@@ -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 (__freertos_check_if_in_isr()) {
__freertos_mutex_take_from_isr(m);
} else {
if (!__freertos_mutex_try_take(m)) {
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;
@@ -57,7 +61,7 @@ CoreMutex::~CoreMutex() {
if (__isFreeRTOS) {
auto m = __get_freertos_mutex_for_ptr(_mutex);
if (__freertos_check_if_in_isr()) {
__freertos_mutex_give_from_isr(m);
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
} else {
__freertos_mutex_give(m);
}
+1
View File
@@ -43,4 +43,5 @@ private:
mutex_t *_mutex;
bool _acquired;
uint8_t _option;
BaseType_t _pxHigherPriorityTaskWoken;
};
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 3
#define ARDUINO_PICO_MINOR 2
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "3.2.1"
#define ARDUINO_PICO_REVISION 2
#define ARDUINO_PICO_VERSION_STR "3.2.2"
+1 -1
View File
@@ -188,7 +188,7 @@ 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
}
+4 -2
View File
@@ -35,6 +35,7 @@ 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));
@@ -43,10 +44,11 @@ extern "C" {
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));
+2 -2
View File
@@ -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
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'3.2.1'
version = u'3.2.2'
# The full version, including alpha/beta/rc tags.
release = u'3.2.1'
release = u'3.2.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+1 -1
View File
@@ -1,7 +1,7 @@
HTTPClient Library
==================
A simple HTTP requestor that can handle both HTTP and HTTP requests is
A simple HTTP requestor 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
View File
@@ -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()
@@ -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);
@@ -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 */
+11 -4
View File
@@ -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));
+1
View File
@@ -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);
+6 -4
View File
@@ -58,8 +58,8 @@ extern "C" {
xSemaphoreTake(mtx, portMAX_DELAY);
}
void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) {
xSemaphoreTakeFromISR(mtx, NULL);
int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) {
return xSemaphoreTakeFromISR(mtx, pxHigherPriorityTaskWoken);
}
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
@@ -70,8 +70,10 @@ extern "C" {
xSemaphoreGive(mtx);
}
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) {
xSemaphoreGiveFromISR(mtx, NULL);
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) {
+16 -7
View File
@@ -48,7 +48,7 @@ I2S::I2S(PinMode direction) {
_freq = 48000;
_arb = nullptr;
_cb = nullptr;
_buffers = 8;
_buffers = 6;
_bufferWords = 0;
_silenceSample = 0;
_isLSBJ = false;
@@ -138,6 +138,7 @@ 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);
@@ -163,7 +164,7 @@ 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]);
@@ -187,10 +188,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 +228,7 @@ int I2S::read() {
case 16:
ret = _holdWord >> 16;
_holdWord <<= 16;
_isHolding -= 32;
_isHolding -= 16;
return ret;
case 24:
case 32:
@@ -399,5 +408,5 @@ int I2S::availableForWrite() {
if (!_running || !_isOutput) {
return 0;
}
return _arb->available();
return available();
}
+9
View File
@@ -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 {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.30201.0",
"version": "1.30202.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
+1 -1
View File
@@ -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.1
version=3.2.2
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3