Compare commits

...
49 Commits
Author SHA1 Message Date
Earle F. Philhower, III f212720484 Update version 2023-01-14 14:34:45 -08:00
Earle F. Philhower, III 1328f78099 Add VCC-GND YD-RP2040 board (#1120)
Fixes #1109
2023-01-14 14:33:52 -08:00
Earle F. Philhower, III 4c234310fd Add hook support to WebServer (#1119)
Implement the method used in the ESP8266 Web Server to allow user apps to hook into
the HTTP server (to support hooked WebSockets, etc._)

Add example of hook usage
2023-01-14 13:35:33 -08:00
Conor Burns f7ee4a868a Add 0xCB Helios (#1117) 2023-01-14 12:19:27 -08:00
Earle F. Philhower, III ae386d4308 Redo boards menu, separate out upload method, add picotool upload (#1112)
Instead of listing each board three times (normal upload, picoprobe,
and pico-debug uploads), list each board once and use a menu to select
the actual upload method.

Also add in picotool as an upload method for those folks who have trouble
with automounting.

Fix #1111
2023-01-13 13:04:24 -08:00
Earle F. Philhower, III ff9f5d3809 Update README.md 2023-01-09 09:55:27 -08:00
Earle F. Philhower, III ce17a6200b Update install.rst 2023-01-09 08:08:57 -08:00
AnachronisticPenguin 8289bbd27b Add additional instructions for Linux Flatpak users (#1105)
Provide instructions for users to override filesystem access restrictions imposed by Flatpak on some installations of the Arduino IDE
2023-01-09 08:03:30 -08:00
Earle F. Philhower, III aeb41f3e70 Handle slave mode I2C restarts (#1104)
Fixes #1100
2023-01-06 12:23:53 -08:00
Earle F. Philhower, III cefea28539 Stop the I2S PIO when I2S::end called (#1103) 2023-01-06 12:23:26 -08:00
Earle F. Philhower, III da26016edf DMA-based ADC input (microphone, analog sensor) (#1101)
Mimics the I2S/PWMAudio/Stream interface for ease of use.

* Fix non-32b DMA size transfer calculation in ABM
* Rename wasHolding to isHolding in the I2S/PWM
  It is the **current** number of bits left, not the past number.
* Add commented microphone example
* Add docs
2023-01-05 16:00:34 -08:00
Earle F. Philhower, III 6bef238772 Update to LittleFS 2.5.1 (only minor updates) (#1099) 2023-01-03 18:51:28 -08:00
Earle F. Philhower, III 02465b48b3 Allow on-the-fly changes to PWMAudio when possible (#1098)
Also fix crash on PWMAudio::end()
2023-01-03 16:02:43 -08:00
Earle F. Philhower, III 94abf9d19f Move analogReadTemp() to C++-only (#1097)
Now that we have a default parameter, need to only allow it in C++ since
default values are not part of C spec.  Should not affect any users since
only legacy code is in C.
2023-01-03 13:30:11 -08:00
Thomas Combriat 7a4244180b Set Right and Left correctly for lsbj format (#1096) 2023-01-03 13:15:08 -08:00
Earle F. Philhower, III 6fe6c474f7 Add LSBJ format support for I2S (#1095)
Fixes #1094
2023-01-03 11:47:55 -08:00
Earle F. Philhower, III be34ed1385 Reduce stack usage of several components (#1093)
Only 4K total stack, so allocating 400 bytes for a local C string
or 600 bytes for a DHCP response is dangerous.  Use static allocations
instead on the heap.
2023-01-02 11:40:51 -08:00
Earle F. Philhower, III 444bb24464 Remove debug printout warnings (#1091)
Exposed by #1090, remove ugly printf format warnings while in debug mode
2023-01-02 10:51:04 -08:00
NuclearPhoenix 0e6ca28316 Update wiring_analog.cpp (#1092) 2023-01-02 10:44:49 -08:00
Earle F. Philhower, III d718b143d2 Warn when Serial.printf() format is wrong (#1090)
Let GCC check the format string to Print::printf().  Will catch when
sketches use incorrect parameters to `Serial::printf()`.
2023-01-01 15:26:15 -08:00
Axotron 1e2f1a19ff Adding sei() and cli() as aliases for interrupts() and noInterrupts(). (#1089) 2023-01-01 14:18:06 -08:00
Earle F. Philhower, III 1228251bc3 Add stereo support, docs for PWM playback (#1084)
Limited to consecutive pins (i.e. GPIOs on the same PWM slice).
"For free" with PWM since no add'l DMA, buffers, or IRQs are needed.
2023-01-01 11:27:49 -08:00
Earle F. Philhower, III a781ec2fdd Add WString.h include redirect for broader compat (#1083)
See #1079
2022-12-31 11:03:28 -08:00
Earle F. Philhower, III 6a30e4b7a4 Update version 2022-12-30 13:28:23 -08:00
Earle F. Philhower, III 08d37de94e Add PWMAudio for DAC-free audio playback (#1076)
Use the PWM hardware to generate a signal suitable for filtering and
amplifying 16bps audio output.

Refactor the AudioBufferManager to allow sharing with I2S

Add example
2022-12-30 13:24:06 -08:00
neilger b8906e0a83 digitalRead/WriteFast to sio_hw->gpio (#1077) 2022-12-30 09:09:04 -08:00
Earle F. Philhower, III 89947f0300 Update analog.rst 2022-12-29 10:35:36 -08:00
NuclearPhoenix 729360379f Universal analogReadTemp() (#1075) 2022-12-29 10:33:49 -08:00
Earle F. Philhower, III c69c568f49 Fix I2S::flush volatile casting (#1074)
Also clean up unneeded includes for I2S
2022-12-29 09:43:26 -08:00
Earle F. Philhower, III 0a58e91523 Reduce ADC memory footprint slightly (#1073)
Saves 28 bytes by using a bitmask and smaller ADC settings globals, see #1072

~1% performance impact so negligible.
2022-12-29 09:31:37 -08:00
Earle F. Philhower, III 5ef04daf44 Make the AudioRingBuffer list-based (#1064)
The ring buffer worked but had issues with IRQs and the available()
procesing.  Because it was a pain to debug, move to a linked list
setup where there are filled and empty buffers to work from,
simplifying the underlying logic.

Allow I2S::available() to return free writing space in OUTPUT mode
to make it saner.

* Increase default number of buffers for 32bps

Gives 2x the time between interrutps to handle I2S callbacks.

* Add setBuffers keyword
2022-12-28 14:46:32 -08:00
Earle F. Philhower, III c9ae04c784 Speed up ADC reads by not re-initting (#1072)
Only change the ADC mux/GPIO control when things re not yet set up.
See #1070
2022-12-28 14:11:24 -08:00
Earle F. Philhower, III 47b18ea84a Add digitalWrite/ReadFast macros (#1069)
* Add digitalWrite/ReadFast macros

Fix #1067

* Update using @neilger's macros
2022-12-28 11:08:18 -08:00
Earle F. Philhower, III dd45bb1694 Update to Adafruyit TinyUSB 1.17 (#1071)
Includes MIDI fixes
2022-12-28 09:05:20 -08:00
Mücahid Kamber e105c539ad Degz Mizu changed to Viyalab Mizu RP2040 (#1062) 2022-12-23 10:43:20 -08:00
Earle F. Philhower, III 4af69f34a2 Update to 1.5.0-a toolchain (#1060)
Newer OpenOCD: sysfsgpio, bcm2835gpio, cmsis-dap-v2 support
Raspberry Pi packaging fixes
2022-12-22 18:16:52 -08:00
Jay Greco 16f5ae7abe Add nullbits Bit-C PRO board (#1051) 2022-12-19 08:50:52 -08:00
Earle F. Philhower, III d184274324 Fix CI errors when more than one *.a in cache dir (#1049)
Avoids errors shown in logs for certain builds.
2022-12-18 14:43:36 -08:00
Earle F. Philhower, III 4cc8e6d6db Update version 2022-12-17 12:07:51 -08:00
brabl2 fecbac2e25 Modified LowPowerMode functions in WiFiClass.cpp/.h for better connection stability (#1046)
* Modified LowPowerMode functions in WiFiClass.cpp/.h

* Added noLowPowerMode() in the WiFiClass::begin()/beginAP()
2022-12-17 11:49:16 -08:00
Earle F. Philhower, III e2e65fd53b Fix I2s::available() to skip currently playing (#1043)
Fixes #963

The available space calculation didn't account for the fact that one
of the buffers was currently being output, causing ::available() to
be too large and ::write() to block in that case.
2022-12-14 15:41:36 -08:00
Earle F. Philhower, III f22ed52b75 Increase ClientContext write(Stream) to 256b chunk (#1042)
Other parts of the core use temp 256 byte chunks to transmit/move/operate
on data, so do the same here.  Will increase effective WebServer sendFile
speeds.
2022-12-14 09:14:57 -08:00
Earle F. Philhower, III 03dbd6af65 Increase WiFi.begin() default timeout to 15s (#1041)
Fixes #1031, or at least covers the case of slower associations.
2022-12-14 08:59:24 -08:00
Earle F. Philhower, III fca7fb5e0f Add USB drive mode to TinyUSB, SingleFileDisk (#1034)
SingleFileDisk allows for exporting a file from the onboard LittleFS
filesystem to a PC through an emulated FAT drive when connected.  The
PC can open and copy the file, as well as delete it, but the PC has no
access to the main onboard LittleFS and no actual on-flash FAT
structures are used.

This is handy for things like data loggers.  They can run connected to
USB power for some time, and then connected to a PC to dowmload the CSV
log recorded.

It's almost 2023, allow LFN (long file names) on the emulated USB disk.

Reduce the disk buffer size to 64 bytes.  The buffer is statically
allocated so it's always present, even in non-USB disk mode, meaning
all apps will pay the RAM price for it.  64 bytes is slower to read
but works and saves ~1/2KB of heap for all apps.
2022-12-09 13:59:23 -08:00
Earle F. Philhower, III 80d6e2f0ec Throw away UART bytes with errors in reception (#1036)
Fixes #1021

The UART hardware will push characters into the receive FIFO even if there
are parity, framing, or other errors.  These are invalid and shouldn't be
returned to the application, so drop them if errors detected.

This will also avoid the glitch-induced initial garbage character.
2022-12-09 12:30:52 -08:00
Eli Lipsitz d35e938c36 Fix File::readString to work with binary data (#1030)
Previously, File::readString used a C-style string as an intermediate
buffer via the String += operator. This treats a NUL byte as a
terminator, making this function work incorrectly if the File contains
binary data.

This commit switches the function to use String::concat, which doesn't
treat NUL bytes any differently (and is a bit faster, because it doesn't
need to use strlen).
2022-12-04 13:23:16 -08:00
Sebastian Krzyszkowiak 4e16a700c6 pluggable_discovery: Allow the scanner thread to quit (#1029)
When receiving a `QUIT` message, the main thread was trying to tell   
the scanner thread to quit - however, what it was actually doing was
creating a local variable that shadowed the global flag used by the
scanner thread. Fix that by ensuring that the main thread uses the
global variable instead.

Fixes #1028
2022-12-04 11:50:06 -08:00
Earle F. Philhower, III d717b58001 Speed up ClientContext::write(Stream) by chunking (#1017)
Instead of sending a single packet per byte, send out larger chunks to
TCP/IP while doing a ::write(Stream).

Fixes #999
2022-11-29 15:00:47 -08:00
Earle F. Philhower, III 861da4c361 Add Waveshare JSONs for Platform.IO (#1015) 2022-11-28 12:26:23 -08:00
96 changed files with 20764 additions and 19240 deletions
+7 -1
View File
@@ -12,6 +12,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
# Supported Boards
* Raspberry Pi Pico
* Raspberry Pi Pico W
* 0xCB Helios
* Adafruit Feather RP2040
* Adafruit Feather RP2040 SCORPIO
* Adafruit ItsyBitsy RP2040
@@ -25,7 +26,6 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Cytron Maker Pi RP2040
* Cytron Maker Nano RP2040
* DatanoiseTV PicoADK+
* Degz Mizu
* DeRuiLab FlyBoard2040 Core
* DFRobot Beetle RP2040
* ElectronicCats Hunter Cat NFC
@@ -40,12 +40,15 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Invector Labs RPICO32
* Melopero Cookie RP2040
* Melopero Shake RP2040
* nullbits Bit-C PRO
* Pimoroni PGA2040
* Seeed XIAO RP2040
* Solder Party RP2040 Stamp
* SparkFun ProMicro RP2040
* SparkFun Thing Plus RP2040
* uPesy RP2040 DevKit
* VCC-GND YD-RP2040
* Viyalab Mizu RP2040
* Waveshare RP2040 Zero
* Waveshare RP2040 One
* Waveshare RP2040 Plus
@@ -167,6 +170,9 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
* FreeRTOS SMP support
* Overclocking and underclocking from the menus
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
* Analog stereo audio in using DMA and the built-in ADC
* Analog stereo audio out using PWM hardware
* USB drive mode for data loggers (SingleFileDrive)
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
* printf (i.e. debug) output over USB serial
+2195 -18564
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -68,10 +68,16 @@ void noInterrupts();
#define portOutputRegister(port) ((volatile uint32_t*) sio_hw->gpio_out)
#define portInputRegister(port) ((volatile uint32_t*) sio_hw->gpio_in)
#define portModeRegister(port) ((volatile uint32_t*) sio_hw->gpio_oe)
#define digitalWriteFast(pin, val) (val ? sio_hw->gpio_set = (1 << pin) : sio_hw->gpio_clr = (1 << pin))
#define digitalReadFast(pin) ((1 << pin) & sio_hw->gpio_in)
#define sei() interrupts()
#define cli() noInterrupts()
// ADC RP2040-specific calls
void analogReadResolution(int bits);
float analogReadTemp(); // Returns core temp in Centigrade
#ifdef __cplusplus
float analogReadTemp(float vref = 3.3); // Returns core temp in Centigrade
#endif
// PWM RP2040-specific calls
void analogWriteFreq(uint32_t freq);
+6 -7
View File
@@ -192,13 +192,12 @@ File File::openNextFile() {
String File::readString() {
String ret;
ret.reserve(size() - position());
char temp[256 + 1];
int countRead = readBytes(temp, sizeof(temp) - 1);
while (countRead > 0) {
temp[countRead] = 0;
ret += temp;
countRead = readBytes(temp, sizeof(temp) - 1);
}
uint8_t temp[256];
int countRead;
do {
countRead = read(temp, sizeof(temp));
ret.concat(temp, countRead);
} while (countRead > 0);
return ret;
}
+174 -4
View File
@@ -33,6 +33,10 @@
#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 <device/usbd_pvt.h>
// Big, global USB mutex, shared with all USB devices to make sure we don't
// have multiple cores updating the TUSB state in parallel
@@ -67,10 +71,18 @@ static int __usb_task_irq;
#define USBD_STR_PRODUCT (0x02)
#define USBD_STR_SERIAL (0x03)
#define USBD_STR_CDC (0x04)
#define USBD_STR_RPI_RESET (0x05)
#define EPNUM_HID 0x83
#define USBD_MSC_EPOUT 0x03
#define USBD_MSC_EPIN 0x84
#define USBD_MSC_EPSIZE 64
#define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, _stridx,
const uint8_t *tud_descriptor_device_cb(void) {
static tusb_desc_device_t usbd_desc_device = {
@@ -89,7 +101,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
.iSerialNumber = USBD_STR_SERIAL,
.bNumConfigurations = 1
};
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick && !__USBInstallMassStorage) {
// Can use as-is, this is the default USB case
return (const uint8_t *)&usbd_desc_device;
}
@@ -103,6 +115,9 @@ const uint8_t *tud_descriptor_device_cb(void) {
if (__USBInstallJoystick) {
usbd_desc_device.idProduct |= 0x0100;
}
if (__USBInstallMassStorage) {
usbd_desc_device.idProduct ^= 0x2000;
}
// Set the device class to 0 to indicate multiple device classes
usbd_desc_device.bDeviceClass = 0;
usbd_desc_device.bDeviceSubClass = 0;
@@ -223,7 +238,7 @@ void __SetupUSBDescriptor() {
if (!usbd_desc_cfg) {
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick;
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0);
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMassStorage ? 1 : 0);
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
@@ -238,7 +253,20 @@ void __SetupUSBDescriptor() {
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
};
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0);
uint8_t msd_itf = interface_count - 1;
uint8_t msd_desc[TUD_MSC_DESC_LEN] = {
TUD_MSC_DESCRIPTOR(msd_itf, 0, USBD_MSC_EPOUT, USBD_MSC_EPIN, USBD_MSC_EPSIZE)
};
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMassStorage ? sizeof(msd_desc) : 0);
#ifdef ENABLE_PICOTOOL_USB
uint8_t picotool_itf = interface_count++;
uint8_t picotool_desc[] = {
TUD_RPI_RESET_DESCRIPTOR(picotool_itf, USBD_STR_RPI_RESET)
};
usbd_desc_len += sizeof(picotool_desc);
#endif
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
// Config number, interface count, string index, total length, attribute, power in mA
@@ -260,6 +288,14 @@ void __SetupUSBDescriptor() {
memcpy(ptr, hid_desc, sizeof(hid_desc));
ptr += sizeof(hid_desc);
}
if (__USBInstallMassStorage) {
memcpy(ptr, msd_desc, sizeof(msd_desc));
ptr += sizeof(msd_desc);
}
#ifdef ENABLE_PICOTOOL_USB
memcpy(ptr, picotool_desc, sizeof(picotool_desc));
ptr += sizeof(picotool_desc);
#endif
}
}
}
@@ -277,6 +313,9 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
[USBD_STR_PRODUCT] = "PicoArduino",
[USBD_STR_SERIAL] = idString,
[USBD_STR_CDC] = "Board CDC",
#ifdef ENABLE_PICOTOOL_USB
[USBD_STR_RPI_RESET] = "Reset",
#endif
};
if (!idString[0]) {
@@ -367,4 +406,135 @@ extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_r
(void) bufsize;
}
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) __attribute__((weak));
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
(void) lun;
(void) lba;
(void) offset;
(void) buffer;
(void) bufsize;
return -1;
}
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) __attribute__((weak));
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
(void) lun;
return false;
}
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) __attribute__((weak));
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
(void) lun;
(void) lba;
(void) offset;
(void) buffer;
(void) bufsize;
return -1;
}
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) __attribute__((weak));
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
(void) lun;
(void) scsi_cmd;
(void) buffer;
(void) bufsize;
return 0;
}
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) __attribute__((weak));
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
(void) lun;
*block_count = 0;
*block_size = 0;
}
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) __attribute__((weak));
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
vendor_id[0] = 0;
product_id[0] = 0;
product_rev[0] = 0;
}
#ifdef ENABLE_PICOTOOL_USB
static uint8_t _picotool_itf_num;
static void resetd_init() {
}
static void resetd_reset(uint8_t rhport) {
(void) rhport;
_picotool_itf_num = 0;
}
static uint16_t resetd_open(uint8_t rhport,
tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
(void) rhport;
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
uint16_t const drv_len = sizeof(tusb_desc_interface_t);
TU_VERIFY(max_len >= drv_len, 0);
_picotool_itf_num = itf_desc->bInterfaceNumber;
return drv_len;
}
// Support for parameterized reset via vendor interface control request
static bool resetd_control_xfer_cb(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request) {
(void) rhport;
// nothing to do with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP) {
return true;
}
if (request->wIndex == _picotool_itf_num) {
if (request->bRequest == RESET_REQUEST_BOOTSEL) {
reset_usb_boot(0, (request->wValue & 0x7f));
// does not return, otherwise we'd return true
}
if (request->bRequest == RESET_REQUEST_FLASH) {
watchdog_reboot(0, 0, 100);
return true;
}
}
return false;
}
static bool resetd_xfer_cb(uint8_t rhport, uint8_t ep_addr,
xfer_result_t result, uint32_t xferred_bytes) {
(void) rhport;
(void) ep_addr;
(void) result;
(void) xferred_bytes;
return true;
}
static usbd_class_driver_t const _resetd_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "RESET",
#endif
.init = resetd_init,
.reset = resetd_reset,
.open = resetd_open,
.control_xfer_cb = resetd_control_xfer_cb,
.xfer_cb = resetd_xfer_cb,
.sof = NULL
};
// Implement callback to add our custom driver
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
*driver_count = 1;
return &_resetd_driver;
}
#endif
#endif
+1
View File
@@ -26,6 +26,7 @@ extern void __USBInstallSerial() __attribute__((weak));
extern void __USBInstallKeyboard() __attribute__((weak));
extern void __USBInstallJoystick() __attribute__((weak));
extern void __USBInstallMouse() __attribute__((weak));
extern void __USBInstallMassStorage() __attribute__((weak));
// Big, global USB mutex, shared with all USB devices to make sure we don't
// have multiple cores updating the TUSB state in parallel
+3 -3
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 2
#define ARDUINO_PICO_MINOR 6
#define ARDUINO_PICO_REVISION 4
#define ARDUINO_PICO_VERSION_STR "2.6.4"
#define ARDUINO_PICO_MINOR 7
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "2.7.1"
+6 -1
View File
@@ -390,7 +390,12 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
// ICR is write-to-clear
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
while (uart_is_readable(_uart)) {
auto val = uart_getc(_uart);
uint32_t raw = uart_get_hw(_uart)->dr;
if (raw & 0x700) {
// Framing, Parity, or Break. Ignore this bad char
continue;
}
uint8_t val = raw & 0xff;
auto next_writer = _writer + 1;
if (next_writer == _fifoSize) {
next_writer = 0;
+1 -1
View File
@@ -109,7 +109,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
if (ret > 0) {
newTone->alarm = ret;
} else {
DEBUGCORE("ERROR: Unable to allocate timer for tone(%d, %d, %d)\n",
DEBUGCORE("ERROR: Unable to allocate timer for tone(%d, %d, %lu)\n",
pin, frequency, duration);
}
}
+1
View File
@@ -0,0 +1 @@
#include "api/String.h"
+26 -10
View File
@@ -26,6 +26,8 @@
#include <hardware/pll.h>
#include <hardware/adc.h>
void __clearADCPin(pin_size_t p);
static uint32_t analogScale = 255;
static uint32_t analogFreq = 1000;
static uint32_t pwmInitted = 0;
@@ -41,10 +43,10 @@ extern "C" void analogWriteFreq(uint32_t freq) {
return;
}
if (freq < 100) {
DEBUGCORE("ERROR: analogWriteFreq too low (%d)\n", freq);
DEBUGCORE("ERROR: analogWriteFreq too low (%lu)\n", freq);
analogFreq = 100;
} else if (freq > 10'000'000) {
DEBUGCORE("ERROR: analogWriteFreq too high (%d)\n", freq);
DEBUGCORE("ERROR: analogWriteFreq too high (%lu)\n", freq);
analogFreq = 10'000'000;
} else {
analogFreq = freq;
@@ -62,7 +64,7 @@ extern "C" void analogWriteRange(uint32_t range) {
pwmInitted = 0;
scaleInitted = false;
} else {
DEBUGCORE("ERROR: analogWriteRange out of range (%d)\n", range);
DEBUGCORE("ERROR: analogWriteRange out of range (%lu)\n", range);
}
}
@@ -81,20 +83,21 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
DEBUGCORE("ERROR: Illegal analogWrite pin (%d)\n", pin);
return;
}
__clearADCPin(pin);
if (!scaleInitted) {
// For low frequencies, we need to scale the output max value up to achieve lower periods
analogWritePseudoScale = 1;
while (((clock_get_hz(clk_sys) / ((float)analogScale * analogFreq)) > 255.0) && (analogScale < 32678)) {
analogWritePseudoScale++;
analogScale *= 2;
DEBUGCORE("Adjusting analogWrite values PS=%d, scale=%d\n", analogWritePseudoScale, analogScale);
DEBUGCORE("Adjusting analogWrite values PS=%d, scale=%lu\n", analogWritePseudoScale, analogScale);
}
// For high frequencies, we need to scale the output max value down to actually hit the frequency target
analogWriteSlowScale = 1;
while (((clock_get_hz(clk_sys) / ((float)analogScale * analogFreq)) < 1.0) && (analogScale >= 6)) {
analogWriteSlowScale++;
analogScale /= 2;
DEBUGCORE("Adjusting analogWrite values SS=%d, scale=%d\n", analogWriteSlowScale, analogScale);
DEBUGCORE("Adjusting analogWrite values SS=%d, scale=%lu\n", analogWriteSlowScale, analogScale);
}
scaleInitted = true;
}
@@ -120,7 +123,13 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
}
auto_init_mutex(_adcMutex);
static int _readBits = 10;
static uint8_t _readBits = 10;
static uint8_t _lastADCMux = 0;
static uint32_t _adcGPIOInit = 0;
void __clearADCPin(pin_size_t p) {
_adcGPIOInit &= ~(1 << p);
}
extern "C" int analogRead(pin_size_t pin) {
CoreMutex m(&_adcMutex);
@@ -136,12 +145,18 @@ extern "C" int analogRead(pin_size_t pin) {
adc_init();
adcInitted = true;
}
adc_gpio_init(pin);
adc_select_input(pin - minPin);
if (!(_adcGPIOInit & (1 << pin))) {
adc_gpio_init(pin);
_adcGPIOInit |= 1 << pin;
}
if (_lastADCMux != pin) {
adc_select_input(pin - minPin);
_lastADCMux = pin;
}
return (_readBits < 12) ? adc_read() >> (12 - _readBits) : adc_read() << (_readBits - 12);
}
extern "C" float analogReadTemp() {
extern "C" float analogReadTemp(float vref) {
CoreMutex m(&_adcMutex);
if (!m) {
@@ -151,12 +166,13 @@ extern "C" float analogReadTemp() {
adc_init();
adcInitted = true;
}
_lastADCMux = 0;
adc_set_temp_sensor_enabled(true);
delay(1); // Allow things to settle. Without this, readings can be erratic
adc_select_input(4); // Temperature sensor
int v = adc_read();
adc_set_temp_sensor_enabled(false);
float t = 27.0f - ((v * 3.3f / 4096.0f) - 0.706f) / 0.001721f; // From the datasheet
float t = 27.0f - ((v * vref / 4096.0f) - 0.706f) / 0.001721f; // From the datasheet
return t;
}
+6
View File
@@ -21,6 +21,8 @@
#include "Arduino.h"
#include <hardware/gpio.h>
extern void __clearADCPin(pin_size_t p);
static PinMode _pm[30];
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
@@ -75,6 +77,10 @@ extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
return;
}
_pm[ulPin] = ulMode;
if ((ulPin >= std::min(A0, A3)) && (ulPin <= std::max(A0, A3))) {
__clearADCPin(ulPin);
}
}
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
+87
View File
@@ -0,0 +1,87 @@
ADC Input Library
=================
The ADC pins can be sampled and recorded by an application using the same
interface as the I2S or PWM Audio libraries. This allows analog devices which
need to be periodically sampled to be read by applications, easily, such as:
* Analog electret microphones
* Potentiometers
* Light dependent resistors (LDR), etc.
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A4``), 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).
The interface for the ``ADCInput`` device is very similar to the ``I2S`` input
device, and most code can be ported simply by instantiating a ``ADCInput``
object in lieu of an ``I2S`` input object and choosing the pins to record.
Since this uses the ADC hardware, no ``analogRead`` or ``analogReadTemp`` calls are
allowed while in use.
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
order (i.e. ``ADCInput(A0, A1);`` is valid, but ``ADCInput(A1, A0)`` is not.
bool setBuffers(size_t buffers, size_t bufferWords)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the number of DMA buffers and their size in 32-bit words. Call before
``ADCInput::begin()``.
When running at high sample rates, it is recommended to increase the
``bufferWords`` to 32 or higher (i.e. ``adcinput.setBuffers(4, 32);`` ).
bool setPins(pin_size_t pin [, pin1, pin2, pin3])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adjusts the pin to record. Only legal before ``ADCInput::begin()``.
bool setFrequency(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the ADC sampling frequency, but does not start recording (however if the
device was already running, it will wontinue to run at the new frequency). Note
that every pin requested will be sampled at this frequency, one after the other.
That is, if you have code like this:
.. code:: cpp
ADCInput adc(A0, A1);
adc.setFrequency(1000);
``A0`` will be sampled at 0ms, 1ms, 2ms, etc. and ``A1`` will be sampled at 0.5ms
1.5ms, 2.5ms, etc. Each input is sampled at the proper frequency but offset in time
since there is only one active ADC at a time.
bool begin()/begin(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the ADC input up with the given sample rate, or with the value set
using the prior ``setFrequency`` call.
void end()
~~~~~~~~~~
Stops the ADC Input device.
int read()
~~~~~~~~~~
Reads a single sample of recorded ADC data, as a 16-bit value. When multiple pins are
recorded the first read will be pin 0, the second will be pin 1, etc. Applications need
to keep track of which pin is being returned (normally by always reading out all pins
at once). Will not return until data is available.
int available()
~~~~~~~~~~~~~~~
Returns the number of samples that can be read without potentially blocking.
void onReceive(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when a ADC input DMA buffer is fully filled.
Will be in an interrupt context so the specified function must operate
quickly and not use blocking calls like delay().
+2 -1
View File
@@ -18,9 +18,10 @@ void analogReadResolution(int bits)
Determines the resolution (in bits) of the value returned by the analogRead() function.
Default resolution is 10bit.
float analogReadTemp()
float analogReadTemp(float vref = 3.3f)
~~~~~~~~~~~~~~~~~~~~~~
Returns the temperature, in Celsius, of the onboard thermal sensor.
If you have a custom Vref for the ADC on your RP2040 board, you can pass it in as a parameter. Calling with no parameters assumes the normal, 3.3V Vref.
This reading is not exceedingly accurate and of relatively low
resolution, so it is not a replacement for an external temperature
sensor in many cases.
+2 -2
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'2.6.4'
version = u'2.7.1'
# The full version, including alpha/beta/rc tags.
release = u'2.6.4'
release = u'2.7.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+6
View File
@@ -58,6 +58,12 @@ Sets the word clock frequency, but does not start the I2S device if not
already running. May be called after ``I2S::begin()`` to change the
sample rate on-the-fly.
bool setLSBJFormat()
~~~~~~~~~~~~~~~~~~~~
Enables LSB-J format for I2S output. In this mode the MSB comes out at the
same time as the LRCLK changes, and not the normal 1-cycle delay. Useful for
DAC chips like the PT8211.
bool begin()/begin(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the I2S device up with the given sample rate, or with the value set
+4
View File
@@ -30,6 +30,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
Digital I/O <digital>
EEPROM <eeprom>
I2S Audio <i2s>
PWM Audio <pwm>
Microphone (and Analog Sensor) Input <adc>
Serial USB and UARTs <serial>
"Software Serial" PIO UART <piouart>
Servo <servo>
@@ -39,6 +41,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
USB (Arduino and Adafruit_TinyUSB) <usb>
Multicore Processing <multicore>
Single File USB Drive <singlefile>
FreeRTOS SMP (multicore) <freertos>
WiFi (Pico-W Support) <wifi>
+34 -8
View File
@@ -9,14 +9,6 @@ installation.
Installing via Arduino Boards Manager
-------------------------------------
**Note for Windows Users**: Please do not use the Windows Store version of
the actual Arduino application because it has issues detecting attached Pico
boards. Use the "Windows ZIP" or plain "Windows" executable (EXE) download
direct from https://arduino.cc. and allow it to install any device drivers
it suggests. Otherwise the Pico board may not be detected. Also, if trying
out the 2.0 beta Arduino please install the release 1.8 version beforehand
to ensure needed device drivers are present.
1. Open up the Arduino IDE and go to File->Preferences.
2. In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
@@ -28,6 +20,24 @@ to ensure needed device drivers are present.
.. image:: images/install2.png
Arduino IDE Installation Warning
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Note for Windows Users**: Please do not use the Windows Store version of
the actual Arduino application because it has issues detecting attached Pico
boards. Use the "Windows ZIP" or plain "Windows" executable (EXE) download
direct from https://arduino.cc. and allow it to install any device drivers
it suggests. Otherwise the Pico board may not be detected. Also, if trying
out the 2.0 beta Arduino please install the release 1.8 version beforehand
to ensure needed device drivers are present.
**Note for Linux Users**: If you installed the Arduino IDE using Flatpak, which
is common in Pop!_OS, Fedora, and Mint, among others, you may need to configure
Flatpak to allow the IDE access to files outside your home folder. The RP2040
device is sometimes mounted as a folder in /opt or /media, which Flatpak will
prevent the Arduino IDE from accessing. For Arduino IDE V2, override the filesystem
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 GIT
------------------
To install via GIT (for latest and greatest versions):
@@ -125,6 +135,22 @@ For detailed usage information, please check the repo documentation available at
* https://arduino-pico.readthedocs.io/en/latest/fs.html
Uploading Sketches with Picotool
--------------------------------
Because the Picotool uses a custom device driver in the Pico to handle upload, when using the ``Upload Method->Picotool`` mode custom code needs to be run on the Pico which is not included by default for compatibility and code savings.
So for the first sketch you will need to rebuild (with the ``Upload Method->Picotool`` selected in them menus) and then manually hold down BOOTSEL and insert the Pico USB cable to enter the ROM bootloader.
After the initial upload, as long as the running binary was built using the ``Picotool`` upload method, then the normal upload process should work.
Note that for Ubuntu and other Linux operating systems you may need to add the following lines to a new `udev` config file(``99-picotool.rules``) to allow normal users to access the special USB device the Pico exports:
.. code::
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-Picotool.rules
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-Picotool.rules
sudo udevadm control --reload
Uploading Sketches with Picoprobe
---------------------------------
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
+97
View File
@@ -0,0 +1,97 @@
PWM Audio Library
=================
Relatively good quality analog audio out can be generated by using the
RP2040 onboard PWM hardware. It can drive an amplifier for speaker output,
or be decoupled using a capacitor to drive a headphone-level signal. Mono
and stereo signals can be generated.
All samples are sent to the ``PWMAudio`` library as **signed 16 bits per sample**.
Due to frequency limitations of the PWM hardware, at higher bit rates
these 16-bits will automatically be reduced to the maximum the hardware
can handle.
Multiple ``PWMAudio`` devices are supported, depending on availability of
DMA channels.
The interface for the ``PWMAudio`` device is very similar to the ``I2S``
device, and most code can be ported simply by instantiating a ``PWMAudio``
object in lieu of an ``I2S`` object.
PWM Class API
-------------
PWMAudio(pin)
~~~~~~~~~~~~~
Creates a mono PWM output port. Any pin can be used, but no ``analogWrite``
calls are allowed to any other pins using that pin's PWM slice hardware.
See the RP2040 datasheet for more details about PWM slices.
PWMAudio(pin, true)
~~~~~~~~~~~~~~~~~~~
Creates a stereo PWM output port. Only even pins (left signal) can be used, the next odd
pin will automatically be assigned to the right channel (i.e. ``PWMAudio pwm(0, true);``
will make GP0 as the left channel, GP1 as the right channel). The same restriction as
in mono mode applies.
bool setBuffers(size_t buffers, size_t bufferWords)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set the number of DMA buffers and their size in 32-bit words.
Call before ``PWMAudio::begin()``.
When running at high sample rates, it is recommended to increase the
``bufferWords`` to 32 or higher (i.e. ``pwm.setBuffers(4, 32);`` ).
bool setPin(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adjusts the pin to connect to the PWM audio output. Only legal before
``PWMAudio::begin()``.
bool setStereo(bool stereo)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adjusts the mono/stereo setting of the PWM audio output. Only legal before
``PWMAudio::begin()``.
bool setFrequency(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the sample frequency, but does not start the PWM device (however if the
device was already running, it will wontinue to run at the new frequency).
bool begin()/begin(long sampleRate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Start the PWM Audio device up with the given sample rate, or with the value set
using the prior ``setFrequency`` call.
void end()
~~~~~~~~~~
Stops the PWMAudio device.
void flush()
~~~~~~~~~~~~
Waits until all the PWM Audio buffers have been output.
size_t write(int16_t sample, bool sync = true)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Writes a single 16-bit sample to the buffer. It is up to the user to keep track
of left/right channels when in stereo mode. In mono mode, one sample is written
per timestep while in stereo mode two ``write()`` calls are required.
This call will block (wait) until space is available to actually write
the data if ``sync`` is not specified or set to ``true``.
size_t write(const uint8_t \*buffer, size_t size)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transfers number of bytes from an application buffer to the PWM Audio output buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes**. Will not block, so check the return value to find out how
many bytes were actually written.
int availableForWrite()
~~~~~~~~~~~~~~~~~~~~~~~
Returns the number of samples that can be written without potentially blocking.
void onTransmit(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when a PWM Audio DMA buffer is fully transmitted.
Will be in an interrupt context so the specified function must operate
quickly and not use blocking calls like delay() or write to the PWM Audio.
+82
View File
@@ -0,0 +1,82 @@
SingleFileDrive
===============
USB drive mode is supported through the ``SingleFileDrive`` class which
allows the Pico to emulate a FAT-formatted USB stick while preserving the
onboard LittleFS filesystem. A single file can be exported this way without
needing to use FAT as the onboard filesystem (FAT is not appropriate for
flash-based devices without complicated wear leveling because of the update
frequency of the FAT tables).
This emulation is very simple and only allows for the reading of the single
file, and deleting it.
Callbacks, Interrupt Safety, and File Operations
------------------------------------------------
The ``SingleFileDrive`` library allows your application to get a callback
when a PC attempts to mount or unmount the Pico as a drive. Your app can
also get a callback if the user attempts to delete the file (but your
sketch does not actually need to delete the file, it's up to you).
Note that when the USB drive is mounted by a PC it is not safe for your
main sketch to make changes to the LittleFS filesystem or the file being
exported. So, normally, your ``onPlug`` callback will set a flag letting
your application know not to touch the filesystem, with the ``onUnplug``
callback clearing this flag.
Also, because the USB port can be connected at any time, it is important
to disable interrupts using ``noInterrupts()`` before writing to a file
you will be exporting (and restoring them with ``interrupts()`` afterwards).
It is also important to ``close()`` the file after each update, or the
on-flash version the ``SingleFileDrive`` will attempt to export may not be
up to date causing issues later on.
See the included ``DataLoggerUSB`` sketch for an example of working with
these limitations.
Using SingleFileDrive
---------------------
Implementing the drive requires including the header file, starting LittleFS,
defining your callbacks, and telling the library what file to export. No
polling or other calls are required outside of your ``setup()``. (Note that
the callback routines allow for a parameter to be passed to them, but in most
cases this can be safely ignored.)
.. code:: cpp
#include <LittleFS.h>
#include <SingleFileDrive.h>
void myPlugCB(uint32_t data) {
// Tell my app not to write to flash, we're connected
}
void myUnplugCB(uint32_t data) {
// I can start writing to flash again
}
void myDeleteDB(uint32_t data) {
// Maybe LittleFS.remove("myfile.txt")? or do nothing
}
void setup() {
LittleFS.begin();
singleFileDrive.onPlug(myPlugCB);
singleFileDrive.onUnplug(myUnplugCB);
singleFileDrive.onDelete(myDeleteCB);
singleFileDrive.begin("littlefsfile.csv", "Data Recorder.csv");
// ... rest of setup ...
}
void loop() {
// Take some measurements, delay, etc.
if (okay-to-write) {
noInterrupts();
File f = LittleFS.open("littlefsfile.csv", "a");
f.printf("%d,%d,%d\n", data1, data2, data3);
f.close();
interrupts();
}
}
+2 -3
View File
@@ -72,15 +72,14 @@
//------------- CLASS -------------//
#define CFG_TUD_HID (2)
#define CFG_TUD_CDC (1)
#define CFG_TUD_MSC (0)
#define CFG_TUD_MSC (1)
#define CFG_TUD_MIDI (0)
#define CFG_TUD_VENDOR (0)
#define CFG_TUD_CDC_RX_BUFSIZE (256)
#define CFG_TUD_CDC_TX_BUFSIZE (256)
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
#define CFG_TUD_MSC_EP_BUFSIZE (64)
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE (64)
+3
View File
@@ -54,6 +54,9 @@ SerialPIO KEYWORD2
setFIFOSize KEYWORD2
setPollingMode KEYWORD2
digitalWriteFast KEYWORD2
digitalReadFast KEYWORD2
enableDoubleResetBootloader KEYWORD2
OUTPUT_2MA LITERAL1
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -9,6 +9,7 @@
-iwithprefixbefore/pico-sdk/src/common/pico_stdlib/include
-iwithprefixbefore/pico-sdk/src/common/pico_sync/include
-iwithprefixbefore/pico-sdk/src/common/pico_time/include
-iwithprefixbefore/pico-sdk/src/common/pico_usb_reset_interface/include
-iwithprefixbefore/pico-sdk/src/common/pico_util/include
-iwithprefixbefore/pico-sdk/src/rp2040/hardware_regs/include
-iwithprefixbefore/pico-sdk/src/rp2040/hardware_structs/include
@@ -0,0 +1,30 @@
/*
Mono analog microphone example using electret mike on A0
Run using the Arduino Serial Plotter to see waveform.
Released to the Public Domain by Earle F. Philhower, III
Wire the mike's VCC to 3.3V on the Pico, connect the mike's
GND to a convenient Pico GND, and then connect mike OUT to A0
*/
#include <ADCInput.h>
ADCInput mike(A0);
// For stereo/dual mikes, could use this line instead
// ADCInput(A0, A1);
void setup() {
Serial.begin(115200);
mike.begin(8000);
while (1) {
Serial.printf("%d\n", mike.read());
// For stereo/dual mikes, use this line instead
// Serial.printf("%d %d\n", mike.read(), mike.read());
}
}
void loop() {
/* Nothing here */
}
+25
View File
@@ -0,0 +1,25 @@
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ADCInput KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
setPins KEYWORD2
setFrequency KEYWORD2
setBuffers KEYWORD2
onReceive KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+10
View File
@@ -0,0 +1,10 @@
name=ADCInput
version=1.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Records ADC values (i.e. microphone, sensors) and presents an I2S-like callback/immediate read interface
paragraph=Records ADC values (i.e. microphone, sensors) and presents an I2S-like callback/immediate read interface
category=Communication
url=http://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
+172
View File
@@ -0,0 +1,172 @@
/*
ADCInput
Records ADC values (i.e. microphone, sensors) and presents an I2S-like
callback/immediate read interface
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 "ADCInput.h"
#include <hardware/adc.h>
ADCInput::ADCInput(pin_size_t p0, pin_size_t p1, pin_size_t p2, pin_size_t p3) {
_running = false;
setPins(p0, p1, p2, p3);
_freq = 48000;
_arb = nullptr;
_cb = nullptr;
_buffers = 8;
_bufferWords = 0;
}
ADCInput::~ADCInput() {
end();
}
bool ADCInput::setBuffers(size_t buffers, size_t bufferWords) {
if (_running || (buffers < 3) || (bufferWords < 8)) {
return false;
}
_buffers = buffers;
_bufferWords = bufferWords;
return true;
}
int ADCInput::_mask(pin_size_t p) {
switch (p) {
case 26: return 1;
case 27: return 2;
case 28: return 4;
case 29: return 8;
default: return 0;
}
}
bool ADCInput::setPins(pin_size_t pin0, pin_size_t pin1, pin_size_t pin2, pin_size_t pin3) {
if (_running) {
return false;
}
_pinMask = _mask(pin0) | _mask(pin1) | _mask(pin2) | _mask(pin3);
return true;
}
bool ADCInput::setFrequency(int newFreq) {
_freq = newFreq * __builtin_popcount(_pinMask); // Want to sample all channels at given frequency
adc_set_clkdiv(48000000.0f / _freq - 1.0f);
return true;
}
void ADCInput::onReceive(void(*fn)(void)) {
_cb = fn;
if (_running) {
_arb->setCallback(_cb);
}
}
bool ADCInput::begin() {
_running = true;
_isHolding = 0;
if (!_bufferWords) {
_bufferWords = 16;
}
// Set up the GPIOs to go to ADC
adc_init();
int cnt = 0;
for (int mask = 1, pin = 26; pin <= 29; mask <<= 1, pin++) {
if (_pinMask & mask) {
if (!cnt) {
adc_select_input(pin - 26);
}
cnt++;
adc_gpio_init(pin);
}
}
adc_set_round_robin(_pinMask);
adc_fifo_setup(true, true, 1, false, false);
setFrequency(_freq);
_arb = new AudioBufferManager(_buffers, _bufferWords, 0, INPUT, DMA_SIZE_16);
_arb->begin(DREQ_ADC, (volatile void*)&adc_hw->fifo);
_arb->setCallback(_cb);
adc_fifo_drain();
adc_run(true);
return true;
}
void ADCInput::end() {
if (_running) {
_running = false;
delete _arb;
_arb = nullptr;
}
adc_run(false);
adc_fifo_drain();
}
int ADCInput::available() {
if (!_running) {
return 0;
} else {
return _arb->available();
}
}
int ADCInput::read() {
if (!_running) {
return -1;
}
if (_hasPeeked) {
_hasPeeked = false;
return _peekSaved;
}
if (_isHolding <= 0) {
_arb->read(&_holdWord, true);
_isHolding = 32;
}
int ret = _holdWord & 0x0fff;
_holdWord >>= 16;
_isHolding -= 16;
return ret;
}
int ADCInput::peek() {
if (!_running) {
return -1;
}
if (!_hasPeeked) {
_peekSaved = read();
_hasPeeked = true;
}
return _peekSaved;
}
void ADCInput::flush() {
if (_running) {
_arb->flush();
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
ADCInput
Records ADC values (i.e. microphone, sensors) and presents an I2S-like
callback/immediate read interface
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 <Arduino.h>
#include "AudioBufferManager.h"
class ADCInput : public Stream {
public:
ADCInput(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255);
virtual ~ADCInput();
bool setBuffers(size_t buffers, size_t bufferWords);
bool setFrequency(int newFreq);
bool setPins(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255);
bool begin(long sampleRate) {
setFrequency(sampleRate);
return begin();
}
bool begin();
void end();
// from Stream
virtual int available() override;
virtual int read() override;
virtual int peek() override;
virtual void flush() override;
// from Print, not supported
virtual size_t write(const uint8_t *buffer, size_t size) override {
(void) buffer;
(void) size;
return -1;
}
virtual size_t write(uint8_t x) override {
(void) x;
return -1;
}
virtual int availableForWrite() override {
return 0;
}
// Note that these callback are called from **INTERRUPT CONTEXT** and hence
// should be in RAM, not FLASH, and should be quick to execute.
void onReceive(void(*)(void));
private:
uint32_t _pinMask;
int _freq;
size_t _buffers;
size_t _bufferWords;
bool _running;
void (*_cb)();
bool _hasPeeked;
uint32_t _peekSaved;
uint32_t _holdWord = 0;
int _isHolding = 0;
int _mask(pin_size_t pin);
AudioBufferManager *_arb;
};
@@ -0,0 +1,10 @@
name=AudioBufferManager
version=1.0.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Manages DMA buffers for audio output
paragraph=Manages DMA buffers for audio output
category=Device Control
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
@@ -0,0 +1,281 @@
/*
AudioBufferManager for Raspnerry Pi Pico RP2040
Implements a DMA controlled linked-list series of buffers
Copyright (c) 2022 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 "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
static AudioBufferManager* __channelMap[12]; // Lets the IRQ handler figure out where to dispatch to
AudioBufferManager::AudioBufferManager(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction, enum dma_channel_transfer_size dmaSize) {
_running = false;
// Need at least 2 DMA buffers and 1 user or this isn't going to work at all
if (bufferCount < 3) {
bufferCount = 3;
}
_bufferCount = bufferCount;
_wordsPerBuffer = bufferWords;
_isOutput = direction == OUTPUT;
_dmaSize = dmaSize;
_overunderflow = false;
_callback = nullptr;
_userOff = 0;
// Create the silence buffer, fill with appropriate value
_silence = new AudioBuffer;
_silence->next = nullptr;
_silence->buff = new uint32_t[_wordsPerBuffer];
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
_silence->buff[x] = silenceSample;
}
// No filled buffers yet
_filled = nullptr;
// Create all buffers on the empty chain
_empty = nullptr;
for (size_t i = 0; i < bufferCount; i++) {
auto ab = new AudioBuffer;
ab->buff = new uint32_t[_wordsPerBuffer];
bzero(ab->buff, _wordsPerBuffer * 4);
ab->next = nullptr;
_addToList(&_empty, ab);
}
_active[0] = _silence;
_active[1] = _silence;
}
AudioBufferManager::~AudioBufferManager() {
if (_running) {
_running = false;
for (auto i = 0; i < 2; i++) {
dma_channel_set_irq0_enabled(_channelDMA[i], false);
__channelMap[_channelDMA[i]] = nullptr;
dma_channel_abort(_channelDMA[i]);
dma_channel_unclaim(_channelDMA[i]);
}
__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??
irq_remove_handler(DMA_IRQ_0, _irq);
}
}
for (int i = 0; i < 2; i++) {
if (_active[i] != _silence) {
_deleteAudioBuffer(_active[i]);
}
}
while (_filled) {
auto x = _filled->next;
_deleteAudioBuffer(_filled);
_filled = x;
}
while (_empty) {
auto x = _empty->next;
_deleteAudioBuffer(_empty);
_empty = x;
}
_deleteAudioBuffer(_silence);
}
void AudioBufferManager::setCallback(void (*fn)()) {
_callback = fn;
}
bool AudioBufferManager::begin(int dreq, volatile void *pioFIFOAddr) {
_running = true;
// Get ping and pong DMA channels
for (auto i = 0; i < 2; i++) {
_channelDMA[i] = dma_claim_unused_channel(true);
if (_channelDMA[i] == -1) {
if (i == 1) {
dma_channel_unclaim(_channelDMA[0]);
}
return false;
}
}
bool needSetIRQ = __channelCount == 0;
// Need to know both channels to set up ping-pong, so do in 2 stages
for (auto i = 0; i < 2; i++) {
dma_channel_config c = dma_channel_get_default_config(_channelDMA[i]);
channel_config_set_transfer_data_size(&c, _dmaSize); // 16b/32b transfers into PIO FIFO
if (_isOutput) {
channel_config_set_read_increment(&c, true); // Reading incrementing addresses
channel_config_set_write_increment(&c, false); // Writing to the same FIFO address
} else {
channel_config_set_read_increment(&c, false); // Reading same FIFO address
channel_config_set_write_increment(&c, true); // Writing to incrememting buffers
}
channel_config_set_dreq(&c, dreq); // Wait for the PIO TX FIFO specified
channel_config_set_chain_to(&c, _channelDMA[i ^ 1]); // Start other channel when done
channel_config_set_irq_quiet(&c, false); // Need IRQs
if (_isOutput) {
dma_channel_configure(_channelDMA[i], &c, pioFIFOAddr, _silence->buff, _wordsPerBuffer * (_dmaSize == DMA_SIZE_16 ? 2 : 1), false);
} else {
_active[i] = _takeFromList(&_empty);
dma_channel_configure(_channelDMA[i], &c, _active[i]->buff, pioFIFOAddr, _wordsPerBuffer * (_dmaSize == DMA_SIZE_16 ? 2 : 1), false);
}
dma_channel_set_irq0_enabled(_channelDMA[i], true);
__channelMap[_channelDMA[i]] = this;
__channelCount++;
}
if (needSetIRQ) {
irq_add_shared_handler(DMA_IRQ_0, _irq, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
irq_set_enabled(DMA_IRQ_0, true);
}
dma_channel_start(_channelDMA[0]);
return true;
}
// Following 2 routines use volatile because the IRQ may update the "this"
// pointer and change the list head while we are waiting. Volatile will
// cause GCC to keep re-reading from memory and not use cached value read
// on the first pass.
bool AudioBufferManager::write(uint32_t v, bool sync) {
if (!_running || !_isOutput) {
return false;
}
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_empty;
if (!*p) {
if (!sync) {
return false;
} else {
while (!*p) {
/* noop busy wait */
}
}
}
(*p)->buff[_userOff++] = v;
if (_userOff == _wordsPerBuffer) {
_addToList(&_filled, _takeFromList(p));
_userOff = 0;
}
return true;
}
bool AudioBufferManager::read(uint32_t *v, bool sync) {
if (!_running || _isOutput) {
return false;
}
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_filled;
if (!*p) {
if (!sync) {
return false;
} else {
while (!*p) {
/* noop busy wait */
}
}
}
auto ret = (*p)->buff[_userOff++];
if (_userOff == _wordsPerBuffer) {
_addToList(&_empty, _takeFromList(p));
_userOff = 0;
}
*v = ret;
return true;
}
bool AudioBufferManager::getOverUnderflow() {
bool hold = _overunderflow;
_overunderflow = false;
return hold;
}
int AudioBufferManager::available() {
AudioBuffer *p = _isOutput ? _empty : _filled;
if (!_running || !p) {
// No buffers available...
return 0;
}
int avail = _wordsPerBuffer - _userOff; // Currently available in this buffer
// Each add'l buffer has wpb spaces...
auto x = p->next;
while (x) {
avail += _wordsPerBuffer;
x = x->next;
}
return avail;
}
void AudioBufferManager::flush() {
AudioBuffer ** volatile a = (AudioBuffer ** volatile)&_active[0];
AudioBuffer ** volatile b = (AudioBuffer ** volatile)&_active[1];
AudioBuffer ** volatile c = (AudioBuffer ** volatile)&_filled;
while (*c && (*b != (AudioBuffer * volatile)_silence) && (*a != (AudioBuffer * volatile)_silence)) {
// busy wait until all user written data enroute
}
}
void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
if (!_running) {
return;
}
if (_isOutput) {
if (_active[0] != _silence) {
_addToList(&_empty, _active[0]);
}
_active[0] = _active[1];
if (!_filled) {
_active[1] = _silence;
} else {
_active[1] = _takeFromList(&_filled);
}
_overunderflow = _overunderflow | (_active[1] == _silence);
dma_channel_set_read_addr(channel, _active[0]->buff, false);
} else {
if (_empty) {
_addToList(&_filled, _active[0]);
_active[0] = _active[1];
_active[1] = _takeFromList(&_empty);
} else {
_overunderflow = true;
}
dma_channel_set_write_addr(channel, _active[0]->buff, false);
}
dma_channel_set_trans_count(channel, _wordsPerBuffer * (_dmaSize == DMA_SIZE_16 ? 2 : 1), false);
dma_channel_acknowledge_irq0(channel);
if (_callback) {
_callback();
}
}
void __not_in_flash_func(AudioBufferManager::_irq)() {
for (size_t i = 0; i < sizeof(__channelMap); i++) {
if (dma_channel_get_irq0_status(i) && __channelMap[i]) {
__channelMap[i]->_dmaIRQ(i);
}
}
}
@@ -0,0 +1,102 @@
/*
AudioBufferManager for Rasperry Pi Pico
Implements a DMA controlled linked-list series of buffers
Copyright (c) 2022 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 <Arduino.h>
#include "hardware/dma.h"
class AudioBufferManager {
public:
AudioBufferManager(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction = OUTPUT, enum dma_channel_transfer_size dmaSize = DMA_SIZE_32);
~AudioBufferManager();
void setCallback(void (*fn)());
bool begin(int dreq, volatile void *pioFIFOAddr);
bool write(uint32_t v, bool sync = true);
bool read(uint32_t *v, bool sync = true);
void flush();
bool getOverUnderflow();
int available();
private:
void _dmaIRQ(int channel);
static void _irq();
typedef struct AudioBuffer {
struct AudioBuffer *next;
uint32_t *buff;
} AudioBuffer;
bool _running = false;
AudioBuffer *_silence = nullptr; // A single silence buffer to be looped on underflow
AudioBuffer *_filled = nullptr; // List of buffers ready to be played
AudioBuffer *_empty = nullptr; // List of buffers waiting to be filled. *_empty = currently writing
AudioBuffer *_active[2] = { nullptr, nullptr }; // The 2 buffers currently in use for DMA
// Can't use std::list because we need to put in RAM for IRQ use, so roll our own
void __not_in_flash_func(_addToList)(AudioBuffer **list, AudioBuffer *element) {
noInterrupts();
// Find end of list, if any
while ((*list) && ((*list)->next != nullptr)) {
list = &(*list)->next;
}
if (*list) {
(*list)->next = element;
} else {
*list = element;
}
element->next = nullptr; // Belt and braces
interrupts();
}
AudioBuffer *__not_in_flash_func(_takeFromList)(AudioBuffer **list) {
noInterrupts();
auto ret = *list;
if (ret) {
*list = ret->next;
}
interrupts();
return ret;
}
void _deleteAudioBuffer(AudioBuffer *ab) {
delete[] ab->buff;
delete ab;
}
int _bitsPerSample;
size_t _wordsPerBuffer;
size_t _bufferCount;
enum dma_channel_transfer_size _dmaSize;
bool _isOutput;
int _channelDMA[2];
void (*_callback)();
bool _overunderflow;
// User buffer pointer
size_t _userOff = 0;
};
@@ -30,7 +30,7 @@ void ps() {
Serial.printf("# Tasks: %d\n", tasks);
Serial.println("ID, NAME, STATE, PRIO, CYCLES");
for (int i=0; i < tasks; i++) {
Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter);
Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], (int)pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter);
}
delete[] pxTaskStatusArray;
}
+2
View File
@@ -18,6 +18,8 @@ setBCLK KEYWORD2
setDATA KEYWORD2
setBitsPerSample KEYWORD2
setFrequency KEYWORD2
setBuffers KEYWORD2
setLSBJFormat KEYWORD2
read8 KEYWORD2
read16 KEYWORD2
-256
View File
@@ -1,256 +0,0 @@
/*
AudioRingBuffer for Raspnerry Pi Pico RP2040
Implements a ring buffer for PIO DMA for I2S read or write
Copyright (c) 2022 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 <vector>
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/pio.h"
#include "pio_i2s.pio.h"
#include "AudioRingBuffer.h"
static int __channelCount = 0; // # of channels left. When we hit 0, then remove our handler
static AudioRingBuffer* __channelMap[12]; // Lets the IRQ handler figure out where to dispatch to
AudioRingBuffer::AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction) {
_running = false;
_silenceSample = silenceSample;
_bufferCount = bufferCount;
_wordsPerBuffer = bufferWords;
_isOutput = direction == OUTPUT;
_overunderflow = false;
_callback = nullptr;
_userBuffer = -1;
_userOff = 0;
for (size_t i = 0; i < bufferCount; i++) {
auto ab = new AudioBuffer;
ab->buff = new uint32_t[_wordsPerBuffer];
ab->empty = true;
_buffers.push_back(ab);
}
}
AudioRingBuffer::~AudioRingBuffer() {
if (_running) {
for (auto i = 0; i < 2; i++) {
dma_channel_set_irq0_enabled(_channelDMA[i], false);
dma_channel_unclaim(_channelDMA[i]);
__channelMap[_channelDMA[i]] = nullptr;
}
while (_buffers.size()) {
auto ab = _buffers.back();
_buffers.pop_back();
delete[] ab->buff;
delete ab;
}
__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??
irq_remove_handler(DMA_IRQ_0, _irq);
}
}
}
void AudioRingBuffer::setCallback(void (*fn)()) {
_callback = fn;
}
bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
_running = true;
// Set all buffers to silence, empty
for (auto buff : _buffers) {
buff->empty = true;
if (_isOutput) {
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
buff->buff[x] = _silenceSample;
}
}
}
// Get ping and pong DMA channels
for (auto i = 0; i < 2; i++) {
_channelDMA[i] = dma_claim_unused_channel(true);
if (_channelDMA[i] == -1) {
if (i == 1) {
dma_channel_unclaim(_channelDMA[0]);
}
return false;
}
}
bool needSetIRQ = __channelCount == 0;
// Need to know both channels to set up ping-pong, so do in 2 stages
for (auto i = 0; i < 2; i++) {
dma_channel_config c = dma_channel_get_default_config(_channelDMA[i]);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32); // 32b transfers into PIO FIFO
if (_isOutput) {
channel_config_set_read_increment(&c, true); // Reading incrementing addresses
channel_config_set_write_increment(&c, false); // Writing to the same FIFO address
} else {
channel_config_set_read_increment(&c, false); // Reading same FIFO address
channel_config_set_write_increment(&c, true); // Writing to incrememting buffers
}
channel_config_set_dreq(&c, dreq); // Wait for the PIO TX FIFO specified
channel_config_set_chain_to(&c, _channelDMA[i ^ 1]); // Start other channel when done
channel_config_set_irq_quiet(&c, false); // Need IRQs
if (_isOutput) {
dma_channel_configure(_channelDMA[i], &c, pioFIFOAddr, _buffers[i]->buff, _wordsPerBuffer, false);
} else {
dma_channel_configure(_channelDMA[i], &c, _buffers[i]->buff, pioFIFOAddr, _wordsPerBuffer, false);
}
dma_channel_set_irq0_enabled(_channelDMA[i], true);
__channelMap[_channelDMA[i]] = this;
__channelCount++;
}
if (needSetIRQ) {
irq_add_shared_handler(DMA_IRQ_0, _irq, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
irq_set_enabled(DMA_IRQ_0, true);
}
_curBuffer = 0;
_nextBuffer = 2 % _bufferCount;
dma_channel_start(_channelDMA[0]);
return true;
}
bool AudioRingBuffer::write(uint32_t v, bool sync) {
if (!_running || !_isOutput) {
return false;
}
if (_userBuffer == -1) {
// First write or overflow, pick spot 2 buffers out
_userBuffer = (_nextBuffer + 2) % _bufferCount;
_userOff = 0;
}
if (!_buffers[_userBuffer]->empty) {
if (!sync) {
return false;
} else {
while (!_buffers[_userBuffer]->empty) {
/* noop busy wait */
}
}
}
if (_userBuffer == _curBuffer) {
if (!sync) {
return false;
} else {
while (_userBuffer == _curBuffer) {
/* noop busy wait */
}
}
}
_buffers[_userBuffer]->buff[_userOff++] = v;
if (_userOff == _wordsPerBuffer) {
_buffers[_userBuffer]->empty = false;
_userBuffer = (_userBuffer + 1) % _bufferCount;
_userOff = 0;
}
return true;
}
bool AudioRingBuffer::read(uint32_t *v, bool sync) {
if (!_running || _isOutput) {
return false;
}
if (_userBuffer == -1) {
// First write or overflow, pick last filled buffer
_userBuffer = (_curBuffer - 1 + _bufferCount) % _bufferCount;
_userOff = 0;
}
if (_buffers[_userBuffer]->empty) {
if (!sync) {
return false;
} else {
while (_buffers[_userBuffer]->empty) {
/* noop busy wait */
}
}
}
if (_userBuffer == _curBuffer) {
if (!sync) {
return false;
} else {
while (_userBuffer == _curBuffer) {
/* noop busy wait */
}
}
}
auto ret = _buffers[_userBuffer]->buff[_userOff++];
if (_userOff == _wordsPerBuffer) {
_buffers[_userBuffer]->empty = true;
_userBuffer = (_userBuffer + 1) % _bufferCount;
_userOff = 0;
}
*v = ret;
return true;
}
bool AudioRingBuffer::getOverUnderflow() {
bool hold = _overunderflow;
_overunderflow = false;
return hold;
}
int AudioRingBuffer::available() {
if (!_running) {
return 0;
}
int avail;
avail = _wordsPerBuffer - _userOff;
avail += ((_bufferCount + _curBuffer - _userBuffer) % _bufferCount) * _wordsPerBuffer;
return avail;
}
void AudioRingBuffer::flush() {
while (_curBuffer != _userBuffer) {
// busy wait
}
}
void __not_in_flash_func(AudioRingBuffer::_dmaIRQ)(int channel) {
if (_isOutput) {
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
_buffers[_curBuffer]->buff[x] = _silenceSample;
}
_buffers[_curBuffer]-> empty = true;
_overunderflow = _overunderflow | _buffers[_nextBuffer]->empty;
dma_channel_set_read_addr(channel, _buffers[_nextBuffer]->buff, false);
} else {
_buffers[_curBuffer]-> empty = false;
_overunderflow = _overunderflow | !_buffers[_nextBuffer]->empty;
dma_channel_set_write_addr(channel, _buffers[_nextBuffer]->buff, false);
}
dma_channel_set_trans_count(channel, _wordsPerBuffer, false);
_curBuffer = (_curBuffer + 1) % _bufferCount;
_nextBuffer = (_nextBuffer + 1) % _bufferCount;
dma_channel_acknowledge_irq0(channel);
if (_callback) {
_callback();
}
}
void __not_in_flash_func(AudioRingBuffer::_irq)() {
for (size_t i = 0; i < sizeof(__channelMap); i++) {
if (dma_channel_get_irq0_status(i) && __channelMap[i]) {
__channelMap[i]->_dmaIRQ(i);
}
}
}
-69
View File
@@ -1,69 +0,0 @@
/*
AudioRingBuffer for Rasperry Pi Pico
Implements a ring buffer for PIO DMA for I2S read or write
Copyright (c) 2022 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 <Arduino.h>
#include <vector>
class AudioRingBuffer {
public:
AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction = OUTPUT);
~AudioRingBuffer();
void setCallback(void (*fn)());
bool begin(int dreq, volatile void *pioFIFOAddr);
bool write(uint32_t v, bool sync = true);
bool read(uint32_t *v, bool sync = true);
void flush();
bool getOverUnderflow();
int available();
private:
void _dmaIRQ(int channel);
static void _irq();
typedef struct {
uint32_t *buff;
volatile bool empty;
} AudioBuffer;
bool _running = false;
std::vector<AudioBuffer*> _buffers;
volatile int _curBuffer;
volatile int _nextBuffer;
size_t _chunkSampleCount;
int _bitsPerSample;
size_t _wordsPerBuffer;
size_t _bufferCount;
bool _isOutput;
int32_t _silenceSample;
int _channelDMA[2];
void (*_callback)();
bool _overunderflow;
// User buffer pointer
int _userBuffer = -1;
size_t _userOff = 0;
};
+47 -25
View File
@@ -49,8 +49,9 @@ I2S::I2S(PinMode direction) {
_arb = nullptr;
_cb = nullptr;
_buffers = 8;
_bufferWords = 16;
_bufferWords = 0;
_silenceSample = 0;
_isLSBJ = false;
}
I2S::~I2S() {
@@ -99,6 +100,14 @@ bool I2S::setFrequency(int newFreq) {
return true;
}
bool I2S::setLSBJFormat() {
if (_running || !_isOutput) {
return false;
}
_isLSBJ = true;
return true;
}
void I2S::onTransmit(void(*fn)(void)) {
if (_isOutput) {
_cb = fn;
@@ -121,10 +130,14 @@ bool I2S::begin() {
_running = true;
_hasPeeked = false;
int off = 0;
_i2s = new PIOProgram(_isOutput ? &pio_i2s_out_program : &pio_i2s_in_program);
_i2s = new PIOProgram(_isOutput ? (_isLSBJ ? &pio_lsbj_out_program : &pio_i2s_out_program) : &pio_i2s_in_program);
_i2s->prepare(&_pio, &_sm, &off);
if (_isOutput) {
pio_i2s_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
if (_isLSBJ) {
pio_lsbj_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
} else {
pio_i2s_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
}
} else {
pio_i2s_in_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
}
@@ -136,7 +149,10 @@ bool I2S::begin() {
uint16_t a = _silenceSample & 0xffff;
_silenceSample = (a << 16) | a;
}
_arb = new AudioRingBuffer(_buffers, _bufferWords, _silenceSample, _isOutput ? OUTPUT : INPUT);
if (!_bufferWords) {
_bufferWords = 16 * (_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]);
_arb->setCallback(_cb);
pio_sm_set_enabled(_pio, _sm, true);
@@ -145,18 +161,24 @@ bool I2S::begin() {
}
void I2S::end() {
_running = false;
delete _arb;
_arb = nullptr;
delete _i2s;
_i2s = nullptr;
if (_running) {
pio_sm_set_enabled(_pio, _sm, false);
_running = false;
delete _arb;
_arb = nullptr;
delete _i2s;
_i2s = nullptr;
}
}
int I2S::available() {
if (!_running || _isOutput) {
if (!_running) {
return 0;
} else if (_isOutput) {
return availableForWrite(); // Do what I mean, not what I say
} else {
return _arb->available();
}
return _arb->available();
}
int I2S::read() {
@@ -169,9 +191,9 @@ int I2S::read() {
return _peekSaved;
}
if (_wasHolding <= 0) {
if (_isHolding <= 0) {
read(&_holdWord, true);
_wasHolding = 32;
_isHolding = 32;
}
int ret;
@@ -179,18 +201,18 @@ int I2S::read() {
case 8:
ret = _holdWord >> 24;
_holdWord <<= 8;
_wasHolding -= 8;
_isHolding -= 8;
return ret;
case 16:
ret = _holdWord >> 16;
_holdWord <<= 16;
_wasHolding -= 32;
_isHolding -= 32;
return ret;
case 24:
case 32:
default:
ret = _holdWord;
_wasHolding = 0;
_isHolding = 0;
return ret;
}
}
@@ -219,26 +241,26 @@ size_t I2S::_writeNatural(int32_t s) {
switch (_bps) {
case 8:
_holdWord |= s & 0xff;
if (_wasHolding >= 24) {
if (_isHolding >= 24) {
auto ret = write(_holdWord, true);
_holdWord = 0;
_wasHolding = 0;
_isHolding = 0;
return ret;
} else {
_holdWord <<= 8;
_wasHolding += 8;
_isHolding += 8;
return 1;
}
case 16:
_holdWord |= s & 0xffff;
if (_wasHolding) {
if (_isHolding) {
auto ret = write(_holdWord, true);
_holdWord = 0;
_wasHolding = 0;
_isHolding = 0;
return ret;
} else {
_holdWord <<= 16;
_wasHolding = 16;
_isHolding = 16;
return 1;
}
case 24:
@@ -295,13 +317,13 @@ bool I2S::read8(int8_t *l, int8_t *r) {
if (!_running || _isOutput) {
return false;
}
if (_wasHolding) {
if (_isHolding) {
*l = (_holdWord >> 8) & 0xff;
*r = (_holdWord >> 0) & 0xff;
_wasHolding = 0;
_isHolding = 0;
} else {
read(&_holdWord, true);
_wasHolding = 16;
_isHolding = 16;
*l = (_holdWord >> 24) & 0xff;
*r = (_holdWord >> 16) & 0xff;
}
+5 -4
View File
@@ -21,8 +21,7 @@
#pragma once
#include <Arduino.h>
#include <vector>
#include "AudioRingBuffer.h"
#include "AudioBufferManager.h"
class I2S : public Stream {
public:
@@ -34,6 +33,7 @@ public:
bool setBitsPerSample(int bps);
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0);
bool setFrequency(int newFreq);
bool setLSBJFormat();
bool begin(long sampleRate) {
setFrequency(sampleRate);
@@ -105,6 +105,7 @@ private:
size_t _buffers;
size_t _bufferWords;
int32_t _silenceSample;
bool _isLSBJ;
bool _isOutput;
bool _running;
@@ -117,11 +118,11 @@ private:
bool _writtenHalf;
int32_t _holdWord = 0;
int _wasHolding = 0;
int _isHolding = 0;
void (*_cb)();
AudioRingBuffer *_arb;
AudioBufferManager *_arb;
PIOProgram *_i2s;
PIO _pio;
int _sm;
+45 -1
View File
@@ -41,6 +41,29 @@ right:
out pins, 1 side 0b00 ; Last bit of right also has WCLK change
; Loop back to beginning...
.program pio_lsbj_out
.side_set 2 ; 0 = bclk, 1=wclk
; The C code should place (number of bits/sample - 2) in Y and
; also update the SHIFTCTRL to be 24 or 32 as appropriate
; +----- WCLK
; |+---- BCLK
mov x, y side 0b01
left:
out pins, 1 side 0b10
jmp x--, left side 0b11
out pins, 1 side 0b10
mov x, y side 0b11
right:
out pins, 1 side 0b00
jmp x--, right side 0b01
out pins, 1 side 0b00
; Loop back to beginning...
.program pio_i2s_in ; Note this is the same as _out, just "in" and not "out"
.side_set 2 ; 0 = bclk, 1=wclk
@@ -73,7 +96,28 @@ static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint
pio_gpio_init(pio, clock_pin_base + 1);
pio_sm_config sm_config = pio_i2s_out_program_get_default_config(offset);
sm_config_set_out_pins(&sm_config, data_pin, 1);
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
pio_sm_init(pio, sm, offset, &sm_config);
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
pio_sm_set_pins(pio, sm, 0); // clear pins
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
}
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
pio_gpio_init(pio, data_pin);
pio_gpio_init(pio, clock_pin_base);
pio_gpio_init(pio, clock_pin_base + 1);
pio_sm_config sm_config = pio_lsbj_out_program_get_default_config(offset);
sm_config_set_out_pins(&sm_config, data_pin, 1);
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
+50 -1
View File
@@ -43,6 +43,41 @@ static inline pio_sm_config pio_i2s_out_program_get_default_config(uint offset)
}
#endif
// ------------ //
// pio_lsbj_out //
// ------------ //
#define pio_lsbj_out_wrap_target 0
#define pio_lsbj_out_wrap 7
static const uint16_t pio_lsbj_out_program_instructions[] = {
// .wrap_target
0xa822, // 0: mov x, y side 1
0x7001, // 1: out pins, 1 side 2
0x1841, // 2: jmp x--, 1 side 3
0x7001, // 3: out pins, 1 side 2
0xb822, // 4: mov x, y side 3
0x6001, // 5: out pins, 1 side 0
0x0845, // 6: jmp x--, 5 side 1
0x6001, // 7: out pins, 1 side 0
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program pio_lsbj_out_program = {
.instructions = pio_lsbj_out_program_instructions,
.length = 8,
.origin = -1,
};
static inline pio_sm_config pio_lsbj_out_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + pio_lsbj_out_wrap_target, offset + pio_lsbj_out_wrap);
sm_config_set_sideset(&c, 2, false, false);
return c;
}
#endif
// ---------- //
// pio_i2s_in //
// ---------- //
@@ -92,6 +127,21 @@ static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint
pio_sm_set_pins(pio, sm, 0); // clear pins
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
}
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
pio_gpio_init(pio, data_pin);
pio_gpio_init(pio, clock_pin_base);
pio_gpio_init(pio, clock_pin_base + 1);
pio_sm_config sm_config = pio_lsbj_out_program_get_default_config(offset);
sm_config_set_out_pins(&sm_config, data_pin, 1);
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
pio_sm_init(pio, sm, offset, &sm_config);
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
pio_sm_set_pins(pio, sm, 0); // clear pins
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
}
static inline void pio_i2s_in_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
pio_gpio_init(pio, data_pin);
pio_gpio_init(pio, clock_pin_base);
@@ -109,4 +159,3 @@ static inline void pio_i2s_in_program_init(PIO pio, uint sm, uint offset, uint d
}
#endif
+2 -2
View File
@@ -457,14 +457,14 @@ public:
if (_creation) {
int rc = lfs_setattr(_fs->getFS(), _name.get(), 'c', (const void *)&_creation, sizeof(_creation));
if (rc < 0) {
DEBUGV("Unable to set creation time on '%s' to %d\n", _name.get(), _creation);
DEBUGV("Unable to set creation time on '%s' to %lld\n", _name.get(), _creation);
}
}
// Add metadata with last write time
time_t now = _timeCallback();
int rc = lfs_setattr(_fs->getFS(), _name.get(), 't', (const void *)&now, sizeof(now));
if (rc < 0) {
DEBUGV("Unable to set last write time on '%s' to %d\n", _name.get(), now);
DEBUGV("Unable to set last write time on '%s' to %lld\n", _name.get(), now);
}
}
}
@@ -0,0 +1,37 @@
/*
This example plays a raw, headerless, mono 16b, 44.1 sample using the PWMAudio library on GPIO 1.
Released to the public domain by Earle F. Philhower, III <earlephilhower@yahoo.com>
*/
#include <PWMAudio.h>
#include "wav.h"
// The sample pointers
const int16_t *start = (const int16_t *)out_raw;
const int16_t *p = start;
// Create the PWM audio device on GPIO 1. Hook amp/speaker between GPIO1 and convenient GND.
PWMAudio pwm(1);
unsigned int count = 0;
void cb() {
while (pwm.availableForWrite()) {
pwm.write(*p++);
count += 2;
if (count >= sizeof(out_raw)) {
count = 0;
p = start;
}
}
}
void setup() {
pwm.onTransmit(cb);
pwm.begin(44100);
}
void loop() {
/* noop, everything is done in the CB */
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,68 @@
/*
This example plays a tune that alternates between left and right channels using a simple sine wave.
Released to the public domain by Earle F. Philhower, III <earlephilhower@yahoo.com>
*/
#include <PWMAudio.h>
PWMAudio pwm(0, true); // GP0 = left, GP1 = right
const int freq = 48000; // Output frequency for PWM
int16_t al = 0;
int16_t ar = 0;
const int notes[] = { 784, 880, 698, 349, 523 };
const int dly[] = { 400, 500, 700, 500, 1000 };
const int noteCnt = sizeof(notes) / sizeof(notes[0]);
int freqL = 1;
int freqR = 1;
double sineTable[128]; // Precompute sine wave in 128 steps
unsigned int cnt = 0;
void cb() {
while (pwm.availableForWrite()) {
double now = ((double)cnt) / (double)freq;
int fl = freqL << 7; // Prescale by 128 to avoid FP math later on
int fr = freqR << 7; // Prescale by 128 to avoid FP math later on
pwm.write((uint16_t)(al * sineTable[(int)(now * fl) & 127]));
pwm.write((uint16_t)(ar * sineTable[(int)(now * fr) & 127]));
cnt++;
}
}
void setup() {
// Set up sine table for waveform generation
for (int i = 0; i < 128; i++) {
sineTable[i] = sin(i * 2.0 * 3.14159 / 128.0);
}
pwm.setBuffers(4, 32); // Give larger buffers since we're are 48khz sample rate
pwm.onTransmit(cb);
pwm.begin(freq);
}
void loop() {
delay(1000);
// Send it out on the LHS
ar = 0;
for (int i = 0; i < noteCnt; i++) {
freqL = notes[i];
al = 5000;
delay(dly[i]);
}
al = 0;
delay(1000);
// Hear reply on RHS
for (int i = 0; i < noteCnt; i++) {
freqR = notes[i] / 4;
ar = 15000;
delay(dly[i]);
}
ar = 0;
delay(3000);
}
+26
View File
@@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
PWMAudio KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
setPin KEYWORD2
setFrequency KEYWORD2
setBuffers KEYWORD2
setStereo KEYWORD2
onTransmit KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+10
View File
@@ -0,0 +1,10 @@
name=PWMAudio
version=1.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Plays audio on a pin using the PWM hardware, no DAC required
paragraph=Plays audio on a pin using the PWM hardware, no DAC required
category=Communication
url=http://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
+211
View File
@@ -0,0 +1,211 @@
/*
PWMAudio
Plays a 16b audio stream on a user defined pin using PWM
Copyright (c) 2022 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 "PWMAudio.h"
#include <hardware/pwm.h>
PWMAudio::PWMAudio(pin_size_t pin, bool stereo) {
_running = false;
_pin = pin;
_freq = 48000;
_arb = nullptr;
_cb = nullptr;
_buffers = 8;
_bufferWords = 0;
_stereo = stereo;
}
PWMAudio::~PWMAudio() {
end();
}
bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) {
if (_running || (buffers < 3) || (bufferWords < 8)) {
return false;
}
_buffers = buffers;
_bufferWords = bufferWords;
return true;
}
bool PWMAudio::setPin(pin_size_t pin) {
if (_running) {
return false;
}
_pin = pin;
return true;
}
bool PWMAudio::setStereo(bool stereo) {
if (_running) {
return false;
}
_stereo = stereo;
return true;
}
bool PWMAudio::setFrequency(int newFreq) {
_freq = newFreq;
// Figure out the scale factor for PWM values
float fPWM = 65535.0 * _freq; // ideal
if (fPWM > clock_get_hz(clk_sys)) {
// Need to downscale the range to hit the frequency target
float pwmMax = (float) clock_get_hz(clk_sys) / (float) _freq;
_pwmScale = pwmMax;
fPWM = clock_get_hz(clk_sys);
} else {
_pwmScale = 1 << 16;
}
pwm_config c = pwm_get_default_config();
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / fPWM);
pwm_config_set_wrap(&c, _pwmScale);
pwm_init(pwm_gpio_to_slice_num(_pin), &c, _running);
gpio_set_function(_pin, GPIO_FUNC_PWM);
pwm_set_gpio_level(_pin, (0x8000 * _pwmScale) >> 16);
if (_stereo) {
gpio_set_function(_pin + 1, GPIO_FUNC_PWM);
pwm_set_gpio_level(_pin + 1, (0x8000 * _pwmScale) >> 16);
}
return true;
}
void PWMAudio::onTransmit(void(*fn)(void)) {
_cb = fn;
if (_running) {
_arb->setCallback(_cb);
}
}
bool PWMAudio::begin() {
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");
return false;
}
_running = true;
_wasHolding = false;
if (!_bufferWords) {
_bufferWords = 16;
}
setFrequency(_freq);
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);
_arb->setCallback(_cb);
return true;
}
void PWMAudio::end() {
if (_running) {
_running = false;
pinMode(_pin, OUTPUT);
if (_stereo) {
pinMode(_pin + 1, OUTPUT);
}
delete _arb;
_arb = nullptr;
}
}
int PWMAudio::available() {
return availableForWrite(); // Do what I mean, not what I say
}
int PWMAudio::read() {
return -1;
}
int PWMAudio::peek() {
return -1;
}
void PWMAudio::flush() {
if (_running) {
_arb->flush();
}
}
int PWMAudio::availableForWrite() {
if (!_running) {
return 0;
}
return _arb->available();
}
size_t PWMAudio::write(int16_t val, bool sync) {
if (!_running) {
return 0;
}
// Go from signed -32K...32K to unsigned 0...64K
uint32_t sample = (uint32_t)(val + 0x8000);
// Adjust to the real range
sample *= _pwmScale;
sample >>= 16;
if (!_stereo) {
// Duplicate sample since we don't care which PWM channel
sample = (sample & 0xffff) | (sample << 16);
return _arb->write(sample, sync);
} else {
if (_wasHolding) {
_holdWord = (_holdWord & 0xffff) | (sample << 16);
auto ret = _arb->write(_holdWord, sync);
if (ret) {
_wasHolding = false;
}
return ret;
} else {
_holdWord = sample;
_wasHolding = true;
return true;
}
}
}
size_t PWMAudio::write(const uint8_t *buffer, size_t size) {
// We can only write 16-bit chunks here
if (size & 0x1) {
return 0;
}
size_t writtenSize = 0;
int16_t *p = (int16_t *)buffer;
while (size) {
if (!write((int16_t)*p)) {
// Blocked, stop write here
return writtenSize;
} else {
p++;
size -= 4;
writtenSize += 4;
}
}
return writtenSize;
}
+87
View File
@@ -0,0 +1,87 @@
/*
PWMAudio
Plays a signed 16b audio stream on a user defined pin using PWM
Copyright (c) 2022 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 <Arduino.h>
#include "AudioBufferManager.h"
class PWMAudio : public Stream {
public:
PWMAudio(pin_size_t pin = 0, bool stereo = false);
virtual ~PWMAudio();
bool setBuffers(size_t buffers, size_t bufferWords);
bool setFrequency(int newFreq);
bool setPin(pin_size_t pin);
bool setStereo(bool stereo = true);
bool begin(long sampleRate) {
setFrequency(sampleRate);
return begin();
}
bool begin();
void end();
// from Stream
virtual int available() override;
virtual int read() override;
virtual int peek() override;
virtual void flush() override;
// from Print (see notes on write() methods below)
virtual size_t write(const uint8_t *buffer, size_t size) override;
virtual int availableForWrite() override;
virtual size_t write(uint8_t x) override {
return write((int16_t) x, true);
}
// Write 16 bit value to port, user responsible for packing/alignment, etc.
size_t write(int16_t val, bool sync = true);
size_t write(int val, bool sync = true) {
return write((int16_t) val, sync);
}
// Note that these callback are called from **INTERRUPT CONTEXT** and hence
// should be in RAM, not FLASH, and should be quick to execute.
void onTransmit(void(*)(void));
private:
pin_size_t _pin;
bool _stereo;
int _freq;
size_t _buffers;
size_t _bufferWords;
uint32_t _pwmScale;
bool _running;
bool _wasHolding;
uint32_t _holdWord;
void (*_cb)();
AudioBufferManager *_arb;
};
+1 -1
View File
@@ -5,6 +5,6 @@ maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Configures requests for OTA bootloader
paragraph=Example repository for Ethernet drivers
category=Device Control
url=https://github.com/earlephilhower.arduino-pico
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
+1 -1
View File
@@ -178,7 +178,7 @@ void SPIClassRP2040::transfer(const void *txbuf, void *rxbuf, size_t count) {
}
void SPIClassRP2040::beginTransaction(SPISettings settings) {
DEBUGSPI("SPI::beginTransaction(clk=%d, bo=%s\n", _spis.getClockFreq(), (_spis.getBitOrder() == MSBFIRST) ? "MSB" : "LSB");
DEBUGSPI("SPI::beginTransaction(clk=%lu, bo=%s\n", _spis.getClockFreq(), (_spis.getBitOrder() == MSBFIRST) ? "MSB" : "LSB");
if (_initted && settings == _spis) {
DEBUGSPI("SPI: Reusing existing initted SPI\n");
} else {
@@ -0,0 +1,92 @@
// Simple logger with USB upload to PC
// Uses SingleFileDrive to export an onboard LittleFS file to the computer
// The PC can open/copy the file, and then the user can delete it to restart
// Released to the public domain, 2022 - Earle F. Philhower, III
#include <SingleFileDrive.h>
#include <LittleFS.h>
uint32_t cnt = 0;
bool okayToWrite = true;
// Make the CSV file and give it a simple header
void headerCSV() {
File f = LittleFS.open("data.csv", "w");
f.printf("sample,millis,temp,rand\n");
f.close();
cnt = 0;
}
// Called when the USB stick connected to a PC and the drive opened
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
void plug(uint32_t i) {
(void) i;
okayToWrite = false;
}
// Called when the USB is ejected or removed from a PC
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
void unplug(uint32_t i) {
(void) i;
okayToWrite = true;
}
// Called when the PC tries to delete the single file
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
void deleteCSV(uint32_t i) {
(void) i;
LittleFS.remove("data.csv");
headerCSV();
}
void setup() {
Serial.begin();
delay(5000);
LittleFS.begin();
// Set up the USB disk share
singleFileDrive.onDelete(deleteCSV);
singleFileDrive.onPlug(plug);
singleFileDrive.onUnplug(unplug);
singleFileDrive.begin("data.csv", "Recorded data from the Raspberry Pi Pico.csv");
// Find the last written data
File f = LittleFS.open("data.csv", "r");
if (!f || !f.size()) {
cnt = 1;
headerCSV();
} else {
if (f.size() > 2048) {
f.seek(f.size() - 1024);
}
do {
String s = f.readStringUntil('\n');
sscanf(s.c_str(), "%lu,", &cnt);
} while (f.available());
f.close();
cnt++;
}
Serial.printf("Starting acquisition at %lu\n", cnt);
}
void loop() {
float temp = analogReadTemp();
uint32_t hwrand = rp2040.hwrand32();
// Make sure the USB connect doesn't happen while we're writing!
noInterrupts();
if (okayToWrite) {
Serial.printf("Sampling...%lu\n", cnt);
// Don't want the USB to connect during an update!
File f = LittleFS.open("data.csv", "a");
if (f) {
f.printf("%lu,%lu,%f,%lu\n", cnt++, millis(), temp, hwrand);
f.close();
}
}
interrupts();
delay(10000);
}
+22
View File
@@ -0,0 +1,22 @@
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SingleFileDrive KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
singleFileDrive KEYWORD1
onDelete KEYWORD1
onPlug KEYWORD1
onUnplug KEYWORD1
#######################################
# Constants (LITERAL1)
#######################################
@@ -0,0 +1,10 @@
name=SingleFileDrive
version=1.0.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Allows using USB MSC (USB stick) to transfer an onboard flash file to a PC
paragraph=Emulates a USB stick and presents a single file for users to copy over/erase
category=Device Control
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
@@ -0,0 +1,395 @@
/*
SingleFileDrive - Emulates a USB stick for easy data transfer
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
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 <SingleFileDrive.h>
#include <LittleFS.h>
#include <class/msc/msc.h>
SingleFileDrive singleFileDrive;
static const uint32_t _hddsize = (256 * 1024 * 1024); // 256MB
static const uint32_t _hddsects = _hddsize / 512;
// Ensure we are logged in to the USB framework
void __USBInstallMassStorage() {
/* dummy */
}
SingleFileDrive::SingleFileDrive() {
}
SingleFileDrive::~SingleFileDrive() {
end();
}
void SingleFileDrive::onDelete(void (*cb)(uint32_t), uint32_t cbData) {
_cbDelete = cb;
_cbDeleteData = cbData;
}
void SingleFileDrive::onPlug(void (*cb)(uint32_t), uint32_t cbData) {
_cbPlug = cb;
_cbPlugData = cbData;
}
void SingleFileDrive::onUnplug(void (*cb)(uint32_t), uint32_t cbData) {
_cbUnplug = cb;
_cbUnplugData = cbData;
}
bool SingleFileDrive::begin(const char *localFile, const char *dosFile) {
if (_started) {
return false;
}
_localFile = strdup(localFile);
_dosFile = strdup(dosFile);
_started = true;
return true;
}
void SingleFileDrive::end() {
_started = false;
free(_localFile);
free(_dosFile);
_localFile = nullptr;
_dosFile = nullptr;
}
void SingleFileDrive::bootSector(char buff[512]) {
// 256MB FAT16 stolen from mkfs.fat
// dd if=/dev/zero of=/tmp/fat.bin bs=1M seek=255 count=1
// mkfs.fat -F 16 -r 16 -n PICODISK -i 12345678 -s 128 -m ':(' /tmp/fat.bin
const uint8_t hdr[] = {
0xeb, 0x3c, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00,
0x02, 0x80, 0x80, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0xf8, 0x80, 0x00,
0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x80, 0x00, 0x29, 0x78, 0x56, 0x34, 0x12, 0x50, 0x49, 0x43, 0x4f, 0x44,
0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20,
0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32,
0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x3a, 0x28, 0x0d, 0x0a, 0x00
};
memset(buff, 0, 512);
memcpy(buff, hdr, sizeof(hdr));
buff[0x1fe] = 0x55;
buff[0x1ff] = 0xff;
}
static char _toLegalFATChar(char c) {
const char *odds = "!#$%&'()-@^_`{}~";
c = toupper(c);
if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || strchr(odds, c)) {
return c;
} else {
return '~';
}
}
void SingleFileDrive::directorySector(char buff[512]) {
const uint8_t lbl[] = {
0x50, 0x49, 0x43, 0x4f, 0x44, 0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x08, 0x00, 0x00, 0xac, 0x56,
0x82, 0x55, 0x82, 0x55, 0x00, 0x00, 0xac, 0x56, 0x82, 0x55
}; //, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
memset(buff, 0, 512);
memcpy(buff, lbl, sizeof(lbl));
buff += 32; // Skip the just-set label
// Create a legal 11-char UPPERCASE FILENAME WITH 0x20 PAD
char SFN[11];
memset(SFN, ' ', 11);
for (int i = 0; (i < 8) && _dosFile[i] && (_dosFile[i] != '.'); i++) {
SFN[i] = _toLegalFATChar(_dosFile[i]);
}
char *dot = _dosFile + strlen(_dosFile) - 1;
while ((dot >= _dosFile) && (*dot != '.')) {
dot--;
}
if (*dot == '.') {
dot++;
for (int i = 0; (i < 3) && dot[i]; i++) {
SFN[8 + i] = _toLegalFATChar(dot[i]);
}
}
uint8_t chksum = 0; // for LFN
for (int i = 0; i < 11; i++) {
chksum = (chksum >> 1) + (chksum << 7) + SFN[i];
}
// Create LFN structure
int entries = (strlen(_dosFile) + 12) / 13; // round up
for (int i = 0; i < entries; i++) {
*buff++ = (entries - i) | (i == 0 ? 0x40 : 0);
const char *partname = _dosFile + 13 * (entries - i - 1);
for (int j = 0; j < 13; j++) {
uint16_t u;
if (j > (int)strlen(partname)) {
u = 0xffff;
} else {
u = partname[j] & 0xff;
}
*buff++ = u & 0xff;
*buff++ = (u >> 8) & 0xff;
if (j == 4) {
*buff++ = 0x0f; // LFN ATTR
*buff++ = 0;
*buff++ = chksum;
} else if (j == 10) {
*buff++ = 0;
*buff++ = 0;
}
}
}
// Create SFN
memset(buff, 0, 32);
for (int i = 0; i < 11; i++) {
buff[i] = SFN[i];
}
buff[0x0b] = 0x20; // ATTR = Archive
// Ignore creation data/time, etc.
buff[0x1a] = 0x03; // Starting cluster 3
File f = LittleFS.open(_localFile, "r");
int size = f.size();
f.close();
buff[0x1c] = size & 255;
buff[0x1d] = (size >> 8) & 255;
buff[0x1e] = (size >> 16) & 255; // 16MB or smaller
}
void SingleFileDrive::fatSector(char fat[512]) {
memset(fat, 0, 512);
fat[0x00] = 0xff;
fat[0x01] = 0xf8;
fat[0x02] = 0xff;
fat[0x03] = 0xff;
int cluster = 3;
File f = LittleFS.open(_localFile, "r");
int size = f.size();
f.close();
while (size > 65536) {
fat[cluster * 2] = (cluster + 1) & 0xff;
fat[cluster * 2 + 1] = ((cluster + 1) >> 8) & 0xff;
cluster++;
size -= 65536;
}
fat[cluster * 2] = 0xff;
fat[cluster * 2 + 1] = 0xff;
}
// Invoked to determine max LUN
extern "C" uint8_t tud_msc_get_maxlun_cb(void) {
return 1;
}
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
const char vid[] = "PicoDisk";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id, vid, strlen(vid));
memcpy(product_id, pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
bool SingleFileDrive::testUnitReady() {
return _started;
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
(void) lun;
return singleFileDrive.testUnitReady();
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
(void) lun;
*block_count = _hddsects;
*block_size = 512;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
(void) lun;
return singleFileDrive.read10(lba, offset, buffer, bufsize);
}
int32_t SingleFileDrive::read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
if (!_started || (lba >= _hddsects)) {
return -1;
}
uint32_t toread = bufsize;
uint8_t *curbuff = (uint8_t *)buffer;
while (bufsize > 0) {
if (lba == 0) {
bootSector(_sectBuff);
} else if ((lba == 128) || (lba == 256)) {
fatSector(_sectBuff);
} else if (lba == 384) {
directorySector(_sectBuff);
} else if (lba >= 640) {
File f = LittleFS.open(_localFile, "r");
f.seek((lba - 640) * 512);
f.read((uint8_t*)_sectBuff, 512);
f.close();
} else {
memset(_sectBuff, 0, sizeof(_sectBuff));
}
uint32_t cplen = 512 - offset;
if (bufsize < cplen) {
cplen = bufsize;
}
memcpy(curbuff, _sectBuff + offset, cplen);
curbuff += cplen;
offset = 0;
lba++;
bufsize -= cplen;
}
return toread;
}
extern "C" bool tud_msc_is_writable_cb(uint8_t lun) {
(void) lun;
return true;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
(void) lun;
return singleFileDrive.write10(lba, offset, buffer, bufsize);
}
int32_t SingleFileDrive::write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
if (!_started || (lba >= _hddsects)) {
return -1;
}
uint32_t addr = lba * 512 + offset;
uint32_t hotspot = 384 * 512 + 0x20;
if ((addr > hotspot) || (addr + bufsize < hotspot)) {
// Did not try and erase the file entry, ignore
return bufsize;
}
int off = hotspot - addr;
uint8_t *ptr = (uint8_t *)buffer;
ptr += off;
if (*ptr == 0xe5) {
if (_cbDelete) {
_cbDelete(_cbDeleteData);
}
}
return bufsize;
}
extern "C" bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
const int SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E;
const int SCSI_CMD_START_STOP_UNIT = 0x1B;
const int SCSI_SENSE_ILLEGAL_REQUEST = 0x05;
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
switch (scsi_cmd[0]) {
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
// Host is about to read/write etc ... better not to disconnect disk
if (scsi_cmd[4] & 1) {
singleFileDrive.plug();
}
resplen = 0;
break;
case SCSI_CMD_START_STOP_UNIT:
// Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
if (!start_stop->start && start_stop->load_eject) {
singleFileDrive.unplug();
} else if (start_stop->start && start_stop->load_eject) {
singleFileDrive.plug();
}
resplen = 0;
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if (resplen > bufsize) {
resplen = bufsize;
}
if (response && (resplen > 0)) {
if (in_xfer) {
memcpy(buffer, response, resplen);
} else {
// SCSI output
}
}
return resplen;
}
void SingleFileDrive::plug() {
if (_started && _cbPlug) {
_cbPlug(_cbPlugData);
}
}
void SingleFileDrive::unplug() {
if (_started && _cbUnplug) {
_cbUnplug(_cbUnplugData);
}
}
// Callback invoked on start/stop
extern "C" bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
(void) lun;
(void) power_condition;
if (start && load_eject) {
singleFileDrive.plug();
} else if (!start && load_eject) {
singleFileDrive.unplug();
}
return true;
}
@@ -0,0 +1,65 @@
/*
SingleFileDrive - Emulates a USB stick for easy data transfer
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
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 <Arduino.h>
class SingleFileDrive {
public:
SingleFileDrive();
~SingleFileDrive();
bool begin(const char *localFile, const char *dosFile);
void end();
void onDelete(void (*cb)(uint32_t), uint32_t cbData = 0);
void onPlug(void (*cb)(uint32_t), uint32_t cbData = 0);
void onUnplug(void (*cb)(uint32_t), uint32_t cbData = 0);
// Only for internal TinyUSB callback use
bool testUnitReady();
int32_t read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
int32_t write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
void plug();;
void unplug();
private:
void bootSector(char buff[512]);
void directorySector(char buff[512]);
void fatSector(char buff[512]);
private:
bool _started = false;
char *_localFile = nullptr;
char *_dosFile = nullptr;
char _sectBuff[512]; // Read sector region
void (*_cbDelete)(uint32_t) = nullptr;
uint32_t _cbDeleteData = 0;
void (*_cbPlug)(uint32_t) = nullptr;
uint32_t _cbPlugData = 0;
void (*_cbUnplug)(uint32_t) = nullptr;
uint32_t _cbUnplugData = 0;
};
extern SingleFileDrive singleFileDrive;
+3 -3
View File
@@ -129,7 +129,7 @@ bool UpdaterClass::begin(size_t size, int command) {
_command = command;
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[begin] _startAddress: 0x%08X (%d)\n"), _startAddress, _startAddress);
DEBUG_UPDATER.printf_P(PSTR("[begin] _startAddress: 0x%08lX (%lu)\n"), _startAddress, _startAddress);
DEBUG_UPDATER.printf_P(PSTR("[begin] _size: 0x%08zX (%zd)\n"), _size, _size);
#endif
@@ -188,7 +188,7 @@ bool UpdaterClass::end(bool evenIfRemaining) {
_fp.read((uint8_t *)&sigLen, sizeof(uint32_t));
}
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[Updater] sigLen: %d\n"), sigLen);
DEBUG_UPDATER.printf_P(PSTR("[Updater] sigLen: %lu\n"), sigLen);
#endif
if (sigLen != expectedSigLen) {
_setError(UPDATE_ERROR_SIGN);
@@ -276,7 +276,7 @@ bool UpdaterClass::end(bool evenIfRemaining) {
picoOTA.addFile("firmware.bin");
picoOTA.commit();
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08X, size:0x%08zX\n"), _startAddress, _size);
DEBUG_UPDATER.printf_P(PSTR("Staged: address:0x%08lX, size:0x%08zX\n"), _startAddress, _size);
#endif
}
@@ -32,6 +32,7 @@
#include <WiFiClient.h>
#include <WebServer.h>
#include <LEAmDNS.h>
#include <StreamString.h>
#ifndef STASSID
#define STASSID "your-ssid"
@@ -48,14 +49,13 @@ const int led = LED_BUILTIN;
void handleRoot() {
static int cnt = 0;
digitalWrite(led, 1);
char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf(temp, 400,
"<html>\
StreamString temp;
temp.reserve(500); // Preallocate a large chunk to avoid memory fragmentation
temp.printf("<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>Pico-W Demo</title>\
@@ -70,9 +70,7 @@ void handleRoot() {
<p>Page Count: %d</p>\
<img src=\"/test.svg\" />\
</body>\
</html>",
hr, min % 60, sec % 60, rp2040.getFreeHeap(), ++cnt);
</html>", hr, min % 60, sec % 60, rp2040.getFreeHeap(), ++cnt);
server.send(200, "text/html", temp);
digitalWrite(led, 0);
}
@@ -0,0 +1,149 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <LEAmDNS.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
WebServer server(80);
const int led = LED_BUILTIN;
void handleRoot() {
digitalWrite(led, 1);
server.send(200, "text/plain", "hello from pico w!\r\n");
digitalWrite(led, 0);
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("picow")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.on("/gif", []() {
static const uint8_t gif[] = {
0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x01,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x19, 0x8c, 0x8f, 0xa9, 0xcb, 0x9d,
0x00, 0x5f, 0x74, 0xb4, 0x56, 0xb0, 0xb0, 0xd2, 0xf2, 0x35, 0x1e, 0x4c,
0x0c, 0x24, 0x5a, 0xe6, 0x89, 0xa6, 0x4d, 0x01, 0x00, 0x3b
};
char gif_colored[sizeof(gif)];
memcpy_P(gif_colored, gif, sizeof(gif));
// Set the background to a random set of colors
gif_colored[16] = millis() % 256;
gif_colored[17] = millis() % 256;
gif_colored[18] = millis() % 256;
server.send(200, "image/gif", gif_colored, sizeof(gif_colored));
});
server.onNotFound(handleNotFound);
/////////////////////////////////////////////////////////
// Hook examples
server.addHook([](const String & method, const String & url, WiFiClient * client, WebServer::ContentTypeFunction contentType) {
(void)method; // GET, PUT, ...
(void)url; // example: /root/myfile.html
(void)client; // the webserver tcp client connection
(void)contentType; // contentType(".html") => "text/html"
Serial.printf("A useless web hook has passed\n");
return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String & url, WiFiClient*, WebServer::ContentTypeFunction) {
if (url.startsWith("/fail")) {
Serial.printf("An always failing web hook has been triggered\n");
return WebServer::CLIENT_MUST_STOP;
}
return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
server.addHook([](const String&, const String & url, WiFiClient * client, WebServer::ContentTypeFunction) {
if (url.startsWith("/dump")) {
Serial.printf("The dumper web hook is on the run\n");
// Here the request is not interpreted, so we cannot for sure
// swallow the exact amount matching the full request+content,
// hence the tcp connection cannot be handled anymore by the
auto last = millis();
while ((millis() - last) < 500) {
char buf[32];
size_t len = client->read((uint8_t*)buf, sizeof(buf));
if (len > 0) {
Serial.printf("(<%d> chars)", (int)len);
Serial.write(buf, len);
last = millis();
}
}
// Two choices: return MUST STOP and webserver will close it
// (we already have the example with '/fail' hook)
// or IS GIVEN and webserver will forget it
// trying with IS GIVEN and storing it on a dumb WiFiClient.
// check the client connection: it should not immediately be closed
// (make another '/dump' one to close the first)
Serial.printf("\nTelling server to forget this connection\n");
static WiFiClient forgetme = *client; // stop previous one if present and transfer client refcounter
return WebServer::CLIENT_IS_GIVEN;
}
return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
});
// Hook examples
/////////////////////////////////////////////////////////
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
MDNS.update();
}
+23 -11
View File
@@ -249,20 +249,32 @@ void HTTPServer::httpHandleClient() {
case HC_WAIT_READ:
// Wait for data from client to become available
if (_currentClient->available()) {
if (_parseRequest(_currentClient)) {
// because HTTP_MAX_SEND_WAIT is expressed in milliseconds,
// it must be divided by 1000
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();
// Fix for issue with Chrome based browsers: https://github.com/espressif/arduino-esp32/issues/3652
// if (_currentClient->connected()) {
// _currentStatus = HC_WAIT_CLOSE;
// _statusChange = millis();
// keepCurrentClient = true;
// }
}
/* 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;
+24 -1
View File
@@ -48,6 +48,8 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
#define WEBSERVER_HAS_HOOK 1
class HTTPServer;
typedef struct {
@@ -183,6 +185,25 @@ public:
return _currentClient->write(file);
}
// Hook
enum ClientFuture { CLIENT_REQUEST_CAN_CONTINUE, CLIENT_REQUEST_IS_HANDLED, CLIENT_MUST_STOP, CLIENT_IS_GIVEN };
typedef String(*ContentTypeFunction)(const String&);
using HookFunction = std::function<ClientFuture(const String& method, const String& url, WiFiClient* client, ContentTypeFunction contentType)>;
void addHook(HookFunction hook) {
if (_hook) {
auto previousHook = _hook;
_hook = [previousHook, hook](const String & method, const String & url, WiFiClient * client, ContentTypeFunction contentType) {
auto whatNow = previousHook(method, url, client, contentType);
if (whatNow == CLIENT_REQUEST_CAN_CONTINUE) {
return hook(method, url, client, contentType);
}
return whatNow;
};
} else {
_hook = hook;
}
}
protected:
virtual size_t _currentClientWrite(const char* b, size_t l) {
return _currentClient->write(b, l);
@@ -193,7 +214,7 @@ protected:
void _addRequestHandler(RequestHandler* handler);
void _handleRequest();
void _finalizeResponse();
bool _parseRequest(WiFiClient* client);
ClientFuture _parseRequest(WiFiClient* client);
void _parseArguments(String data);
static String _responseCodeToString(int code);
bool _parseForm(WiFiClient* client, String boundary, uint32_t len);
@@ -249,4 +270,6 @@ protected:
String _snonce; // Store noance and opaque for future comparison
String _sopaque;
String _srealm; // Store the Auth realm between Calls
HookFunction _hook;
};
+13 -6
View File
@@ -78,7 +78,7 @@ static char* readBytesWithTimeout(WiFiClient* client, size_t maxLength, size_t&
return buf;
}
bool HTTPServer::_parseRequest(WiFiClient* client) {
HTTPServer::ClientFuture HTTPServer::_parseRequest(WiFiClient* client) {
// Read the first line of HTTP request
String req = client->readStringUntil('\r');
client->readStringUntil('\n');
@@ -93,7 +93,7 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
log_e("Invalid request: %s", req.c_str());
return false;
return CLIENT_MUST_STOP;
}
String methodStr = req.substring(0, addr_start);
@@ -110,6 +110,13 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
_chunked = false;
_clientContentLength = 0; // not known yet, or invalid
if (_hook) {
auto whatNow = _hook(methodStr, url, client, mime::getContentType);
if (whatNow != CLIENT_REQUEST_CAN_CONTINUE) {
return whatNow;
}
}
HTTPMethod method = HTTP_ANY;
size_t num_methods = sizeof(_http_method_str) / sizeof(const char *);
for (size_t i = 0; i < num_methods; i++) {
@@ -120,7 +127,7 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
}
if (method == HTTP_ANY) {
log_e("Unknown HTTP Method: %s", methodStr.c_str());
return false;
return CLIENT_MUST_STOP;
}
_currentMethod = method;
@@ -186,7 +193,7 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
char* plainBuf = readBytesWithTimeout(client, _clientContentLength, plainLength, HTTP_MAX_POST_WAIT);
if ((int)plainLength < (int)_clientContentLength) {
free(plainBuf);
return false;
return CLIENT_MUST_STOP;
}
if (_clientContentLength > 0) {
if (isEncoded) {
@@ -214,7 +221,7 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
// it IS a form
_parseArguments(searchStr);
if (!_parseForm(client, boundaryStr, _clientContentLength)) {
return false;
return CLIENT_MUST_STOP;
}
}
} else {
@@ -249,7 +256,7 @@ bool HTTPServer::_parseRequest(WiFiClient* client) {
log_v("Request: %s", url.c_str());
log_v(" Arguments: %s", searchStr.c_str());
return true;
return CLIENT_REQUEST_CAN_CONTINUE;
}
bool HTTPServer::_collectHeader(const char* headerName, const char* headerValue) {
@@ -113,7 +113,7 @@ void loop() {
client.setTrustAnchors(&cert);
fetchURL(&client, host, port, path);
finish = millis();
Serial.printf("Total time: %dms\n", finish - start);
Serial.printf("Total time: %lums\n", finish - start);
BearSSL::Session session;
client.setSession(&session);
@@ -122,21 +122,21 @@ void loop() {
client.setTrustAnchors(&cert);
fetchURL(&client, host, port, path);
finish = millis();
Serial.printf("Total time: %dms\n", finish - start);
Serial.printf("Total time: %lums\n", finish - start);
Serial.printf("Connecting with the just initialized session...");
start = millis();
client.setTrustAnchors(&cert);
fetchURL(&client, host, port, path);
finish = millis();
Serial.printf("Total time: %dms\n", finish - start);
Serial.printf("Total time: %lums\n", finish - start);
Serial.printf("Connecting again with the initialized session...");
start = millis();
client.setTrustAnchors(&cert);
fetchURL(&client, host, port, path);
finish = millis();
Serial.printf("Total time: %dms\n", finish - start);
Serial.printf("Total time: %lums\n", finish - start);
delay(10000); // Avoid DDOSing github
}
@@ -76,7 +76,7 @@ void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_
} while (millis() < to);
}
client->stop();
Serial.printf("BSSL stack used: %d\n-------\n\n", stack_thunk_get_max_usage());
Serial.printf("BSSL stack used: %lu\n-------\n\n", stack_thunk_get_max_usage());
}
void fetchNoConfig() {
@@ -24,7 +24,7 @@ const char *encToString(uint8_t enc) {
void loop() {
delay(5000);
Serial.printf("Beginning scan at %d\n", millis());
Serial.printf("Beginning scan at %lu\n", millis());
auto cnt = WiFi.scanNetworks();
if (!cnt) {
Serial.printf("No networks found\n");
@@ -34,7 +34,7 @@ void loop() {
for (auto i = 0; i < cnt; i++) {
uint8_t bssid[6];
WiFi.BSSID(i, bssid);
Serial.printf("%32s %5s %17s %2d %4d\n", WiFi.SSID(i), encToString(WiFi.encryptionType(i)), macToString(bssid), WiFi.channel(i), WiFi.RSSI(i));
Serial.printf("%32s %5s %17s %2d %4ld\n", WiFi.SSID(i), encToString(WiFi.encryptionType(i)), macToString(bssid), WiFi.channel(i), WiFi.RSSI(i));
}
}
Serial.printf("\n--- Sleeping ---\n\n\n");
+2 -1
View File
@@ -57,7 +57,8 @@ beginEnterprise KEYWORD2
setHostname KEYWORD2
end KEYWORD2
getTime KEYWORD2
lowPowerMode KEYWORD2
aggressiveLowPowerMode KEYWORD2
defaultLowPowerMode KEYWORD2
noLowPowerMode KEYWORD2
ping KEYWORD2
beginMulticast KEYWORD2
+9 -2
View File
@@ -99,6 +99,7 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
if (!_wifi.begin()) {
return WL_IDLE_STATUS;
}
noLowPowerMode();
// Enable CYW43 event debugging (make sure Debug Port is set)
//cyw43_state.trace_flags = 0xffff;
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
@@ -134,6 +135,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
if (!_wifi.begin()) {
return WL_IDLE_STATUS;
}
noLowPowerMode();
IPAddress gw = _wifi.gatewayIP();
if (!gw.isSet()) {
gw = IPAddress(192, 168, 42, 1);
@@ -565,14 +567,19 @@ unsigned long WiFiClass::getTime() {
return millis();
}
void WiFiClass::lowPowerMode() {
void WiFiClass::aggressiveLowPowerMode() {
cyw43_wifi_pm(&cyw43_state, CYW43_AGGRESSIVE_PM);
}
void WiFiClass::noLowPowerMode() {
void WiFiClass::defaultLowPowerMode() {
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM);
}
// The difference between the default CYW43_DEFAULT_PM (0xA11142) and not low power (0xA11140) is that it changed from "Powersave mode on specified interface with High throughput" to "No Powersave mode". All other parameters stayed the same.
void WiFiClass::noLowPowerMode() {
cyw43_wifi_pm(&cyw43_state, 0xA11140);
}
int WiFiClass::ping(const char* hostname, uint8_t ttl) {
IPAddress ip;
if (!hostByName(hostname, ip)) {
+3 -2
View File
@@ -368,7 +368,8 @@ public:
unsigned long getTime();
void lowPowerMode();
void aggressiveLowPowerMode();
void defaultLowPowerMode();
void noLowPowerMode();
int ping(const char* hostname, uint8_t ttl = 128);
@@ -381,7 +382,7 @@ public:
void feedWatchdog();
private:
int _timeout = 10000;
int _timeout = 15000;
String _ssid;
String _password;
bool _wifiHWInitted = false;
+1 -1
View File
@@ -78,7 +78,7 @@ uint8_t WiFiMulti::run(uint32_t to) {
for (int i = 0; i < cnt; i++) {
if (WiFi.RSSI(i) > maxRSSID) {
for (auto j = _list.begin(); j != _list.end(); j++) {
DEBUGV("[WIFIMULTI] Checking for '%s' at %d\n", WiFi.SSID(i), WiFi.RSSI(i));
DEBUGV("[WIFIMULTI] Checking for '%s' at %ld\n", WiFi.SSID(i), WiFi.RSSI(i));
if (!strcmp(j->ssid, WiFi.SSID(i))) {
hit = j;
maxRSSID = WiFi.RSSI(i);
+2 -2
View File
@@ -184,8 +184,8 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
(void)src_addr;
(void)src_port;
// This is around 548 bytes
dhcp_msg_t dhcp_msg;
// This is around 548 bytes, so make static so it will live in the heap, not the stack (too large)
static dhcp_msg_t dhcp_msg;
#define DHCP_MIN_SIZE (240 + 3)
if (p->tot_len < DHCP_MIN_SIZE) {
+15 -5
View File
@@ -374,12 +374,22 @@ public:
return 0;
}
size_t sent = 0;
uint8_t buff[256];
while (stream.available()) {
char b;
b = stream.read();
if (write(&b, 1)) {
sent ++;
// Stream only lets you read 1 byte at a time, so buffer in local copy
size_t i;
for (i = 0; (i < sizeof(buff)) && stream.available(); i++) {
buff[i] = stream.read();
}
if (i) {
// Send as a single packet
int len = write((const char *)buff, i);
sent += len;
if (len != (int)i) {
break; // Write error...
}
} else {
// Out of data...
break;
}
}
@@ -641,7 +651,7 @@ protected:
void _error(err_t err) {
(void) err;
DEBUGV(":er %d 0x%08x\r\n", (int) err, (uint32_t) _datasource);
DEBUGV(":er %d 0x%08lx\r\n", (int) err, (uint32_t) _datasource);
tcp_arg(_pcb, nullptr);
tcp_sent(_pcb, nullptr);
tcp_recv(_pcb, nullptr);
+3
View File
@@ -182,6 +182,9 @@ void TwoWire::onIRQ() {
if (_onReceiveCallback && _buffLen) {
_onReceiveCallback(_buffLen);
}
_buffLen = 0;
_buffOff = 0;
_slaveStartDet = false;
_i2c->hw->clr_restart_det;
}
// STOP_DET
@@ -6,7 +6,7 @@ void setup() {
uint32_t a = rp2040.getCycleCount();
delay(1000);
uint32_t b = rp2040.getCycleCount();
Serial.printf("There are %d cycles in one second.\n\n\n", b - a);
Serial.printf("There are %lu cycles in one second.\n\n\n", b - a);
delay(3000);
@@ -16,6 +16,6 @@ void setup() {
}
void loop() {
Serial.printf("%15u - %15llu\n", rp2040.getCycleCount(), rp2040.getCycleCount64());
Serial.printf("%15lu - %15llu\n", rp2040.getCycleCount(), rp2040.getCycleCount64());
delay(1500);
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.20604.0",
"version": "1.20701.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
+2
View File
@@ -111,6 +111,8 @@ sed 's/^tools.uf2conv.network_cmd=.*//g' | \
sed 's/^#tools.uf2conv.network_cmd=/tools.uf2conv.network_cmd=/g' | \
sed 's/^tools.picoprobe.cmd=.*//g' | \
sed 's/^#tools.picoprobe.cmd=/tools.picoprobe.cmd=/g' | \
sed 's/^tools.picotool.cmd=.*//g' | \
sed 's/^#tools.picotool.cmd=/tools.picotool.cmd=/g' | \
sed 's/^tools.picodebug.cmd=.*//g' | \
sed 's/^#tools.picodebug.cmd=/tools.picodebug.cmd=/g' | \
sed 's/^discovery.rp2040.pattern=.*//g' | \
+217 -148
View File
@@ -23,6 +23,9 @@
{
"name": "Raspberry Pi Pico W"
},
{
"name": "0xCB Helios"
},
{
"name": "Adafruit Feather RP2040"
},
@@ -62,9 +65,6 @@
{
"name": "DatanoiseTV PicoADK"
},
{
"name": "Degz Mizu"
},
{
"name": "DeRuiLab FlyBoard2040Core"
},
@@ -110,6 +110,9 @@
{
"name": "Melopero Shake RP2040"
},
{
"name": "nullbits Bit-C PRO"
},
{
"name": "Pimoroni PGA2040"
},
@@ -128,6 +131,12 @@
{
"name": "Seeed XIAO RP2040"
},
{
"name": "VCC-GND YD RP2040"
},
{
"name": "Viyalab Mizu RP2040"
},
{
"name": "Waveshare RP2040 Zero"
},
@@ -162,22 +171,22 @@
"toolsDependencies": [
{
"packager": "rp2040",
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-gcc"
},
{
"packager": "rp2040",
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-mklittlefs"
},
{
"packager": "rp2040",
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-elf2uf2"
},
{
"packager": "rp2040",
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-pioasm"
},
{
@@ -187,8 +196,13 @@
},
{
"packager": "rp2040",
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-openocd"
},
{
"packager": "rp2040",
"version": "1.5.0-a-03f2812",
"name": "pqt-picotool"
}
],
"help": {
@@ -198,57 +212,112 @@
],
"tools": [
{
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-03f2812",
"name": "pqt-picotool",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.picotool-03f2812.230113.tar.gz",
"archiveFileName": "aarch64-linux-gnu.picotool-03f2812.230113.tar.gz",
"checksum": "SHA-256:3816240a6aef8da61895227df3b1b5d7a7f95456a9e7737e25252886f649d2f3",
"size": "171807"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.picotool-03f2812.230113.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.picotool-03f2812.230113.tar.gz",
"checksum": "SHA-256:454e1a0ce9a546626bca73cdff74dfb0e06bf6603b13d5a3a4a4f0c0968fd65d",
"size": "152809"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.picotool-03f2812.230113.tar.gz",
"archiveFileName": "i686-linux-gnu.picotool-03f2812.230113.tar.gz",
"checksum": "SHA-256:fee7f93d65bb3db42a9fcf5683e2b038ab13875b1d5bedb304facb92e6469a37",
"size": "183571"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.picotool-03f2812.230112.zip",
"archiveFileName": "i686-w64-mingw32.picotool-03f2812.230112.zip",
"checksum": "SHA-256:8a37063d44e306b9315618962cd8dc14b815e998ba960a38099e45bb14bcda90",
"size": "352766"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.picotool-03f2812.230112.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.picotool-03f2812.230112.tar.gz",
"checksum": "SHA-256:5b2f77ee33a7a757546ab526d3e477300bf01e787e645f64aa86daac6b19a510",
"size": "852449"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.picotool-03f2812.230113.tar.gz",
"archiveFileName": "x86_64-linux-gnu.picotool-03f2812.230113.tar.gz",
"checksum": "SHA-256:c6168c6948ec781ead9637ecddc357004aa0fbaca19a634a48fbfc4e48860d1a",
"size": "131509"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.picotool-03f2812.230112.zip",
"archiveFileName": "x86_64-w64-mingw32.picotool-03f2812.230112.zip",
"checksum": "SHA-256:a5bded215b886bc8dc35520d2ae696c56e370ef6e92ca7d3a47fe82db362afa7",
"size": "337118"
}
]
},
{
"version": "1.5.0-a-5007782",
"name": "pqt-openocd",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:8da4fd922fd7392e87c0057b193e67962606cd13450af935c9846992f2bce916",
"size": "5607131"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.openocd-228ede43d.221223.tar.gz",
"archiveFileName": "aarch64-linux-gnu.openocd-228ede43d.221223.tar.gz",
"checksum": "SHA-256:aa3f7a24af6afca5bacd9172f943f59d1f7ca9a3525e7e9c445dba9f8c6c8b68",
"size": "5807317"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:ce7650961c8200fe2cc2d4a88efc952fe1bb7b4175f2cf650a9a7d992ae08298",
"size": "5344149"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.openocd-228ede43d.221223.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.openocd-228ede43d.221223.tar.gz",
"checksum": "SHA-256:40a623e198eccafaec210e3f1b425369e6fe79cef0d94b7a910d63223c37cc50",
"size": "5538300"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:9391ae74c6474f685f45ccefb82e18f382f1a59f3e13e2b22fe00967264d2482",
"size": "5168334"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.openocd-228ede43d.221223.tar.gz",
"archiveFileName": "i686-linux-gnu.openocd-228ede43d.221223.tar.gz",
"checksum": "SHA-256:b80eb819e302130bde5ed303f23645e615bc2440303223d924742ee89dc6d477",
"size": "5341706"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.openocd-e3428fadb.220714.zip",
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220714.zip",
"checksum": "SHA-256:f4b7803527a0a587fe95e52bcf056fcbe58d64b78705edd38810655d3abee1fe",
"size": "2156831"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.openocd-228ede43d.221223.zip",
"archiveFileName": "i686-w64-mingw32.openocd-228ede43d.221223.zip",
"checksum": "SHA-256:02d9fba9d4e66de31cd99af0ade3a6150d258d034aa5f85f7f4601c849b8bc80",
"size": "2207879"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:4e6a8da43758941478e6740e023ea5be051f09bf92e49d65c2b54a1ca4a2660c",
"size": "2002508"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.openocd-228ede43d.221223.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.openocd-228ede43d.221223.tar.gz",
"checksum": "SHA-256:f92b87bd2ec81260c4c76e9e74ede41888d943ac0a97c11ec5f579d450ba72b1",
"size": "2599689"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:2518c6451c0e4c148c8c6cb9330e216075177003b064c509b168f42a44a6eb5a",
"size": "5540574"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.openocd-228ede43d.221223.tar.gz",
"archiveFileName": "x86_64-linux-gnu.openocd-228ede43d.221223.tar.gz",
"checksum": "SHA-256:cf4c30151c9f4583964579f11ffbc66229508b21d83d2f1d7c87eb28d1f0cca9",
"size": "5727971"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
"checksum": "SHA-256:c2da993d74152ec8ca80b350ede77ee94942518081a48dafd7a3b49631778e75",
"size": "2156831"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.openocd-228ede43d.221223.zip",
"archiveFileName": "x86_64-w64-mingw32.openocd-228ede43d.221223.zip",
"checksum": "SHA-256:5f0c4f67f0bba6cf3b9968ba27796fe98ef8787e56f0a160dede8d05d578586c",
"size": "2168940"
}
]
},
@@ -315,222 +384,222 @@
]
},
{
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-gcc",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:0bc906c2eb4b3999285ea8a71ec0c95a20a21f2ff46b1bdd264f2fd3c30fe580",
"size": "77889379"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"checksum": "SHA-256:baff843fce38393565babf81ecfddfab17df8046d901faad3c5f93ee072d395b",
"size": "81474410"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:2bf9f691d1fa97cea3b835a364fc24d06102181725001a00fe3e77526f90e2bd",
"size": "73342377"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.arm-none-eabi-5007782.221223.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-5007782.221223.tar.gz",
"checksum": "SHA-256:35144f4aded62ab45ab7ddabf63c189af70b57534438cf00281c11b5ef90d316",
"size": "76138344"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:e0fe347f2602247ffbc16bb7b74653fdb78c4f75b90037f2e82fc5498b5d1cb9",
"size": "79511866"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"archiveFileName": "i686-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"checksum": "SHA-256:d1d5121c4a5e4fa42047daf58c112a90beeb3533d1f133f4928db4b337030351",
"size": "83712710"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"checksum": "SHA-256:d1ee0f00c97dc50dc06487d6fb6b5dd94bbb3cf1579c975bcd23d7a7922e53b7",
"size": "82626868"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.arm-none-eabi-5007782.221223.zip",
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-5007782.221223.zip",
"checksum": "SHA-256:71e0858689b644e5b0aaa07ec5257919ab292ff9404bfc9c52dc31593828f391",
"size": "85628083"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:1b030451a5a6ddf42ac796c46b2f077f90f6d56586f4537a3486ce47670996cd",
"size": "82119254"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.arm-none-eabi-5007782.221223.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-5007782.221223.tar.gz",
"checksum": "SHA-256:ad984927785d17ddd34cfc7bc76d4d1371d6f6905d8708d3535a261b244b32d9",
"size": "84968911"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:73d032ba42d33f6e9c1d5de79b73bf5e9740b8e6b7fee37de3db03814c553694",
"size": "80363125"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
"checksum": "SHA-256:591af0c27b08b31d11b3135a56bbd3c447cd9e6cac2987cdb3ab25a86d7eb3e3",
"size": "83660106"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"checksum": "SHA-256:3f67e15adbe49ebaee72734e9d469bd6b34fd1be30ccdb6e55a1e05a0be4e1db",
"size": "86064664"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.arm-none-eabi-5007782.221223.zip",
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-5007782.221223.zip",
"checksum": "SHA-256:f2cf872ce5bd07efa2cfa044de28458034be9466f5ccae4e7e9cd229aabefa11",
"size": "88351413"
}
]
},
{
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-elf2uf2",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:14d7c1be08151bcddcc19fdb5741bf52b435f08f52daff2d498a07c5ebfb5bfb",
"size": "82682"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"checksum": "SHA-256:266151dc2523ec707b88256e7220a5e89c819ad1e134a7f492cf9fbe07ccf8a1",
"size": "82684"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:31b790b5a19bbb5950212098aa42be43702fb4db50aa541c9f40b2320e2280be",
"size": "55991"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.elf2uf2-2e6142b.221223.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2e6142b.221223.tar.gz",
"checksum": "SHA-256:e30f1243259361a635a21d69e81bf2d913e194882159eba8c652d5b45cf2591b",
"size": "55998"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:a3dd93861857fd81f8c9ed01509a0af012f446f23f405bc696f6a4d2f344262c",
"size": "91386"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"archiveFileName": "i686-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"checksum": "SHA-256:17ebb211916bc74a9cd3263f6d5e9721bb91d54a836c4369c1e01e9147e4f477",
"size": "91387"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"archiveFileName": "i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"checksum": "SHA-256:25d6a934643074590c3006468ec051f62d02298abbff27d7e3643ee147e818e0",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.elf2uf2-2e6142b.221223.zip",
"archiveFileName": "i686-w64-mingw32.elf2uf2-2e6142b.221223.zip",
"checksum": "SHA-256:80f740ffdb0a1812212f631598060216361b1a8e55d2092e729afee3b3b1ad95",
"size": "71949"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:f2743d086d1992599d656aaa9a38a736d443bdc96619fd5bcabdc7fcb05225c8",
"size": "86600"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.elf2uf2-2e6142b.221223.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2e6142b.221223.tar.gz",
"checksum": "SHA-256:bebf3f984c59b36cfdc1a5b41bc3368c674c03eea54586419872c0ce2ad71430",
"size": "86604"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:5b0e79bfd9d7e5f4d5e5cb0e6e2b685e10fdf3071139c00bf6274a5ca9b9717e",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
"checksum": "SHA-256:d7d0e77a8b4c5cf879bb92d20bbfb213d568fec86fb96fc08c60bd9a3fb38712",
"size": "82339"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"checksum": "SHA-256:f09e022cbb1fe73315ccf16a2af6bc687b64d0c44066f801fb9dee8326e941b1",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.elf2uf2-2e6142b.221223.zip",
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2e6142b.221223.zip",
"checksum": "SHA-256:25840973640fd28817a37a4213dfbad81da91a7b75a1ecb14cdee56c2bd1a8ee",
"size": "80399"
}
]
},
{
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-pioasm",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:d4ac4b39841984178babd75f5c09cad87e06bd2fb18cf04e40f561d72e604a5d",
"size": "453440"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"archiveFileName": "aarch64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"checksum": "SHA-256:38ae80646805781c1df2264ae6b8ff41cc0dbfcefd4dfaae9f5e355bce4890c7",
"size": "453442"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:568ebdd7b1a47c6dbf45793f9bf019855a1b14182fbeb7ed7e342979c6632eef",
"size": "360675"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.pioasm-2e6142b.221223.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.pioasm-2e6142b.221223.tar.gz",
"checksum": "SHA-256:3ab67c8b0f40806e8e2a53fe22b274f3b79ccc12189ab80dc2db3b4e80e34de2",
"size": "360686"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:2abac2bef690f7ffadfcf74af4832bfcc0e212606efbed21b385bda0517554ef",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"archiveFileName": "i686-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"checksum": "SHA-256:ed5d190b3726caa58a63b08785aff17f6f412810cc7bef21405a6342717e6c6b",
"size": "511442"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.pioasm-2e6142b.220714.zip",
"archiveFileName": "i686-w64-mingw32.pioasm-2e6142b.220714.zip",
"checksum": "SHA-256:0b1336b999a31d164248248d37fa550aa14a06dae8ef5b215818c5f0597ca80b",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.pioasm-2e6142b.221223.zip",
"archiveFileName": "i686-w64-mingw32.pioasm-2e6142b.221223.zip",
"checksum": "SHA-256:713be116f8fbdd7a77ae294f2b8a72fcfcb0bd43f013124bde6e569dd284ad43",
"size": "385882"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:7057ba222a54ff9bd43a6a4232a6355100f29e0cc20d3facb5d600180f418e68",
"size": "480538"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.pioasm-2e6142b.221223.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.pioasm-2e6142b.221223.tar.gz",
"checksum": "SHA-256:16feb332e66b8ed7f911eceb153484565d1947a87eb7c9db774bd38a9a7b0043",
"size": "480539"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:30b367e8d2cd4ccdf151e728b4137bad1d993c42f0d640307e27d5fc55fce2c0",
"size": "458691"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"archiveFileName": "x86_64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
"checksum": "SHA-256:367b14d59bb5394c068bacd1ab3dfd77116208ad28213af01372d5a93bb0ead3",
"size": "458693"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
"checksum": "SHA-256:b7b340862e673f9e57287f02219b2d56094a497fe9d8c451acf28aaef721e038",
"size": "409101"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.pioasm-2e6142b.221223.zip",
"archiveFileName": "x86_64-w64-mingw32.pioasm-2e6142b.221223.zip",
"checksum": "SHA-256:c18d5499308c4938b1c2230724f3adb2de8071583b9185b77705747555c9a50f",
"size": "409100"
}
]
},
{
"version": "1.4.0-c-0196c06",
"version": "1.5.0-a-5007782",
"name": "pqt-mklittlefs",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:ad0af70d568e10a9a2a74c6e0a3cf8659a47b80fbf594b01731579bc21a5c212",
"size": "47287"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"archiveFileName": "aarch64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"checksum": "SHA-256:6e20ef3f0c8f4eedd18377cd8e7626a724b3c11ce914e66e23fe021493b519b6",
"size": "60993"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:f8f1a1dd7b02220f11cf0f6a6c88692f7e056eb245fbc41017c33d333751980e",
"size": "40826"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.mklittlefs-30b7fc1.221223.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-30b7fc1.221223.tar.gz",
"checksum": "SHA-256:092501f939d78625f876644a5c1d3264f2310e1798ea6d12a2845274a50a0b54",
"size": "51573"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:4d10a2bc6a8fa41a7e5642aa30128f797f84b099e1bb2282c6c2d62a06e81e21",
"size": "50925"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"archiveFileName": "i686-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"checksum": "SHA-256:c2d8b5d8c903b024ae88bd5a97d9759049fbc1e7ab84ea19ea6ea2546f0aa496",
"size": "67720"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.mklittlefs-affa497.220714.zip",
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220714.zip",
"checksum": "SHA-256:71117412351ea2486848848d76f4d1e3c7a507a4d7546f6b0646bbc10c96d557",
"size": "334062"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
"archiveFileName": "i686-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
"checksum": "SHA-256:9f66d5b6bdfce13b1c246ae2d8abfcab623828337a16a1f2571eeed1b71096b9",
"size": "345497"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:b3d0c30f942982337cd4c0e4f70855f8eabcf1d378eac78465c7fee39ab5915f",
"size": "365780"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.mklittlefs-30b7fc1.221223.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-30b7fc1.221223.tar.gz",
"checksum": "SHA-256:1f7e675700ff4b5de21d1ea37a0969683ad54685d94bf0b42de13c26aa42f13f",
"size": "377123"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:9241e8e642748048bd32c7ccf4a8200e8bc104d6e328fe7437e8727866f29d94",
"size": "49787"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"archiveFileName": "x86_64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
"checksum": "SHA-256:2773b0e7a5af33052b84959893cd9e7f3223236730f2109546399ec52d6a7a70",
"size": "62741"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
"checksum": "SHA-256:2f39dd727e9cb61dbc631d00f543a99b6224fb24ffde0dff0cb2b70c9561ae69",
"size": "347612"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
"checksum": "SHA-256:ee9a6caad229cd9530465926c755a4dc68a89bd5a6ff642c060dfa05f0c01a2a",
"size": "357313"
}
]
}
+10 -2
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=2.6.4
version=2.7.1
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
@@ -28,6 +28,7 @@ runtime.tools.pqt-mklittlefs.path={runtime.platform.path}/system/mklittlefs
runtime.tools.pqt-pioasm.path={runtime.platform.path}/system/pioasm
runtime.tools.pqt-elf2uf2.path={runtime.platform.path}/system/elf2uf2
runtime.tools.pqt-openocd.path={runtime.platform.path}/system/openocd
runtime.tools.pqt-picotool.path={runtime.platform.path}/system/picotool
compiler.path={runtime.tools.pqt-gcc.path}/bin/
compiler.libraries.ldflags=
@@ -44,7 +45,7 @@ compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-ignored-qualif
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 {build.lwipdefs} -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines} -DARDUINO_VARIANT="{build.variant}" -DTARGET_RP2040
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/include"
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect} {build.flags.cmsis}
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect} {build.flags.cmsis} {build.picodebugflags}
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
compiler.libbearssl="{runtime.platform.path}/lib/libbearssl.a"
@@ -97,6 +98,7 @@ build.boot2=boot2_generic_03h_4_padded_checksum
build.lwipdefs=-DLWIP_IPV6=0 -DLWIP_IPV4=1
build.wificc=-DWIFICC=CYW43_COUNTRY_WORLDWIDE
build.debugscript=picoprobe.tcl
build.picodebugflags=
# Allow Pico boards do be auto-discovered by the IDE
#discovery.rp2040.pattern={runtime.tools.pqt-python3.path}/python3 -I "{runtime.platform.path}/tools/pluggable_discovery.py"
@@ -187,6 +189,12 @@ tools.uf2conv-network.upload.params.verbose=
tools.uf2conv-network.upload.params.quiet=
tools.uf2conv-network.upload.pattern="{cmd}" -I "{runtime.platform.path}/tools/espota.py" -i "{upload.port.address}" -p "{upload.port.properties.port}" "--auth={upload.field.password}" -f "{build.path}/{build.project_name}.bin"
#tools.picotool.cmd={runtime.tools.pqt-picotool.path}
tools.picotool.cmd={runtime.platform.path}/system/picotool
tools.picotool.upload.protocol=picotool
tools.picotool.upload.params.verbose=
tools.picotool.upload.params.quiet=
tools.picotool.upload.pattern="{cmd}/picotool" load "{build.path}/{build.project_name}.uf2" -f
#tools.picoprobe.cmd={runtime.tools.pqt-openocd.path}
tools.picoprobe.cmd={runtime.platform.path}/system/openocd
+2 -1
View File
@@ -80,7 +80,8 @@ function build_sketches()
continue # Not ours to do
fi
if [ -e $cache_dir/core/*.a ]; then
cacheas=( $cache_dir/core/*.a )
if [ -e ${cacheas[0]} ]; then
# We need to preserve the build.options.json file and replace the last .ino
# with this sketch's ino file, or builder will throw everything away.
jq '."sketchLocation" = "'$sketch'"' $build_dir/build.options.json > $build_dir/build.options.json.tmp
+3 -3
View File
@@ -1,8 +1,8 @@
#!/bin/bash
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
./libraries/LittleFS/src ./libraries/LittleFS/examples \
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleFileDrive \
./libraries/LittleFS/src ./libraries/LittleFS/examples ./libraries/PWMAudio \
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat ./libraries/ADCInput \
./libraries/Servo ./libraries/SPI ./libraries/Wire ./libraries/PDM \
./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43 \
./libraries/FreeRTOS/src ./libraries/LEAmDNS ./libraries/MD5Builder \
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x1209",
"usb_pid": "0xCB74"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_0XCB_HELIOS -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x1209",
"0xCB74"
]
],
"mcu": "rp2040",
"variant": "0xcb_helios"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "Helios",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 16777216,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "0xCB"
}
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25x10cl_4_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x6E61"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_NULLBITS_BIT_C_PRO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x6E61"
]
],
"mcu": "rp2040",
"variant": "nullbits_bit_c_pro"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "Bit-C PRO",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 4194304,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "nullbits"
}
@@ -9,7 +9,7 @@
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_DEGZ_MIZU -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
"extra_flags": "-D ARDUINO_VIYALAB_MIZU_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
"f_cpu": "133000000L",
"hwids": [
[
@@ -22,7 +22,7 @@
]
],
"mcu": "rp2040",
"variant": "degz_mizu"
"variant": "viyalab_mizu"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -32,7 +32,7 @@
"frameworks": [
"arduino"
],
"name": "Mizu",
"name": "Mizu RP2040",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 8388608,
@@ -50,5 +50,5 @@
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Degz"
"vendor": "Viyalab"
}
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x1021"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_LCD_0_96 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x1021"
]
],
"mcu": "rp2040",
"variant": "waveshare_rp2040_lcd_0_96"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "RP2040 LCD 0.96",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 2097152,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Waveshare"
}
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x1039"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_LCD_1_28 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x1039"
]
],
"mcu": "rp2040",
"variant": "waveshare_rp2040_lcd_1_28"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "RP2040 LCD 1.28",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 2097152,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Waveshare"
}
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x103A"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_ONE -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x103A"
]
],
"mcu": "rp2040",
"variant": "waveshare_rp2040_one"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "RP2040 One",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 4194304,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Waveshare"
}
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x1020"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_PLUS -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x1020"
]
],
"mcu": "rp2040",
"variant": "waveshare_rp2040_plus_16mb"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "RP2040 Plus 16MB",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 16777216,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Waveshare"
}
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2E8A",
"usb_pid": "0x1020"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_PLUS -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
],
[
"0x2E8A",
"0x1020"
]
],
"mcu": "rp2040",
"variant": "waveshare_rp2040_plus_4mb"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "RP2040 Plus 4MB",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 4194304,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Waveshare"
}
+2 -3
View File
@@ -72,15 +72,14 @@
//------------- CLASS -------------//
#define CFG_TUD_HID (2)
#define CFG_TUD_CDC (1)
#define CFG_TUD_MSC (0)
#define CFG_TUD_MSC (1)
#define CFG_TUD_MIDI (0)
#define CFG_TUD_VENDOR (0)
#define CFG_TUD_CDC_RX_BUFSIZE (256)
#define CFG_TUD_CDC_TX_BUFSIZE (256)
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
#define CFG_TUD_MSC_EP_BUFSIZE (64)
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE (64)
+63 -58
View File
@@ -79,8 +79,6 @@ def BuildUSBStack(name):
print('%s.menu.usbstack.picosdk.build.usbstack_flags=' % (name))
print("%s.menu.usbstack.tinyusb=Adafruit TinyUSB" % (name))
print('%s.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"' % (name))
def BuildWithoutUSBStack(name):
print("%s.menu.usbstack.nousb=No USB" % (name))
print('%s.menu.usbstack.nousb.build.usbstack_flags="-DNO_USB -DDISABLE_USB_SERIAL -I{runtime.platform.path}/tools/libpico"' % (name))
@@ -103,7 +101,26 @@ def BuildIPStack(name):
print('%s.menu.ipstack.ipv4ipv6.build.libpico=libpico-ipv6.a' % (name))
print('%s.menu.ipstack.ipv4ipv6.build.lwipdefs=-DLWIP_IPV6=1 -DLWIP_IPV4=1' % (name))
def BuildHeader(name, vendor_name, product_name, vidtouse, pidtouse, vid, pid, pwr, boarddefine, variant, uploadtool, networkuploadtool, flashsize, ramsize, boot2, dbg, extra):
def BuildUploadMethodMenu(name):
for a, b, c, d, e, f in [ ["default", "Default (UF2)", 256, "picoprobe.tcl", "uf2conv", "uf2conv-network"],
["picotool", "Picotool", 256, "picoprobe.tcl", "picotool", None],
["picoprobe", "Picoprobe", 256, "picoprobe.tcl", "picoprobe", None],
["picodebug", "Pico-Debug", 240, "picodebug.tcl", "picodebug", None] ]:
print("%s.menu.uploadmethod.%s=%s" % (name, a, b))
print("%s.menu.uploadmethod.%s.build.ram_length=%dk" % (name, a, c))
print("%s.menu.uploadmethod.%s.build.debugscript=%s" % (name, a, d))
# For pico-debug, need to disable USB unconditionally
if a == "picodebug":
print("%s.menu.uploadmethod.%s.build.picodebugflags=-UUSE_TINYUSB -DNO_USB -DDISABLE_USB_SERIAL -I{runtime.platform.path}/tools/libpico" % (name, a))
elif a == "picotool":
print("%s.menu.uploadmethod.%s.build.picodebugflags=-DENABLE_PICOTOOL_USB" % (name, a))
print("%s.menu.uploadmethod.%s.upload.maximum_data_size=%d" % (name, a, c * 1024))
print("%s.menu.uploadmethod.%s.upload.tool=%s" % (name, a, e))
print("%s.menu.uploadmethod.%s.upload.tool.default=%s" % (name, a, e))
if f != None:
print("%s.menu.uploadmethod.%s.upload.tool.network=%s" % (name, a, f))
def BuildHeader(name, vendor_name, product_name, vid, pid, pwr, boarddefine, variant, flashsize, boot2, extra):
prettyname = vendor_name + " " + product_name
print()
print("# -----------------------------------")
@@ -111,17 +128,17 @@ def BuildHeader(name, vendor_name, product_name, vidtouse, pidtouse, vid, pid, p
print("# -----------------------------------")
print("%s.name=%s" % (name, prettyname))
usb = 0
if type(pidtouse) == list:
if type(pid) == list:
for tp in pid:
print("%s.vid.%d=%s" % (name, usb, vidtouse))
print("%s.vid.%d=%s" % (name, usb, vid))
print("%s.pid.%d=0x%04x" % (name, usb, int(tp, 16)))
usb = usb + 1
else:
for kb in [ "0", "0x8000" ]:
for ms in [ "0", "0x4000" ]:
for jy in [ "0", "0x0100" ]:
thispid = int(pidtouse, 16) | int(kb, 16) | int(ms, 16) | int(jy, 16)
print("%s.vid.%d=%s" % (name, usb, vidtouse))
thispid = int(pid, 16) | int(kb, 16) | int(ms, 16) | int(jy, 16)
print("%s.vid.%d=%s" % (name, usb, vid))
print("%s.pid.%d=0x%04x" % (name, usb, thispid))
usb = usb + 1
if type(pid) == list:
@@ -132,12 +149,7 @@ def BuildHeader(name, vendor_name, product_name, vidtouse, pidtouse, vid, pid, p
print("%s.build.board=%s" % (name, boarddefine))
print("%s.build.mcu=cortex-m0plus" % (name))
print("%s.build.variant=%s" % (name, variant))
print("%s.upload.tool=%s" % (name, uploadtool))
print("%s.upload.tool.default=%s" % (name, uploadtool))
if networkuploadtool != None:
print("%s.upload.tool.network=%s" % (name, networkuploadtool))
print("%s.upload.maximum_size=%d" % (name, flashsize))
print("%s.upload.maximum_data_size=%d" % (name, ramsize))
print("%s.upload.wait_for_upload_port=true" % (name))
print("%s.upload.erase_cmd=" % (name))
print("%s.serial.disableDTR=false" % (name))
@@ -146,8 +158,6 @@ def BuildHeader(name, vendor_name, product_name, vidtouse, pidtouse, vid, pid, p
print("%s.build.led=" % (name))
print("%s.build.core=rp2040" % (name))
print("%s.build.ldscript=memmap_default.ld" % (name))
print("%s.build.ram_length=%dk" % (name, ramsize / 1024))
print("%s.build.debugscript=%s" % (name, dbg))
print("%s.build.boot2=%s" % (name, boot2))
print("%s.build.vid=%s" % (name, vid))
if type(pid) == list:
@@ -182,49 +192,34 @@ def BuildGlobalMenuList():
print("menu.wificountry=WiFi Region")
print("menu.usbstack=USB Stack")
print("menu.ipstack=IP Stack")
print("menu.uploadmethod=Upload Method")
def MakeBoard(name, vendor_name, product_name, vid, pid, pwr, boarddefine, flashsizemb, boot2, extra = None):
for a, b, c, d in [ ["", "", "uf2conv", "uf2conv-network"], ["picoprobe", " (Picoprobe)", "picoprobe", None], ["picodebug", " (pico-debug)", "picodebug", None]]:
n = name + a
p = product_name + b
fssizelist = [ 0, 64 * 1024, 128 * 1024, 256 * 1024, 512 * 1024 ]
for i in range(1, flashsizemb):
fssizelist.append(i * 1024 * 1024)
vidtouse = vid;
ramsizekb = 256;
dbg = "picoprobe.tcl"
if a == "picoprobe":
pidtouse = '0x0004'
elif a == "picodebug":
vidtouse = '0x1209'
pidtouse = '0x2488'
ramsizekb = 240;
dbg = "picodebug.tcl"
else:
pidtouse = pid
BuildHeader(n, vendor_name, p, vidtouse, pidtouse, vid, pid, pwr, boarddefine, name, c, d, flashsizemb * 1024 * 1024, ramsizekb * 1024, boot2, dbg, extra)
if name == "generic":
BuildFlashMenu(n, 2*1024*1024, [0, 1*1024*1024])
BuildFlashMenu(n, 4*1024*1024, [0, 2*1024*1024])
BuildFlashMenu(n, 8*1024*1024, [0, 4*1024*1024])
BuildFlashMenu(n, 16*1024*1024, [0, 8*1024*1024])
else:
BuildFlashMenu(n, flashsizemb * 1024 * 1024, fssizelist)
BuildFreq(n)
BuildOptimize(n)
BuildRTTI(n)
BuildStackProtect(n)
BuildExceptions(n)
BuildDebugPort(n)
BuildDebugLevel(n)
if a != "picodebug":
BuildUSBStack(n)
BuildWithoutUSBStack(n)
if name == "rpipicow":
BuildCountry(n)
BuildIPStack(n)
if name == "generic":
BuildBoot(n)
fssizelist = [ 0, 64 * 1024, 128 * 1024, 256 * 1024, 512 * 1024 ]
for i in range(1, flashsizemb):
fssizelist.append(i * 1024 * 1024)
BuildHeader(name, vendor_name, product_name, vid, pid, pwr, boarddefine, name, flashsizemb * 1024 * 1024, boot2, extra)
if name == "generic":
BuildFlashMenu(name, 2*1024*1024, [0, 1*1024*1024])
BuildFlashMenu(name, 4*1024*1024, [0, 2*1024*1024])
BuildFlashMenu(name, 8*1024*1024, [0, 4*1024*1024])
BuildFlashMenu(name, 16*1024*1024, [0, 8*1024*1024])
else:
BuildFlashMenu(name, flashsizemb * 1024 * 1024, fssizelist)
BuildFreq(name)
BuildOptimize(name)
BuildRTTI(name)
BuildStackProtect(name)
BuildExceptions(name)
BuildDebugPort(name)
BuildDebugLevel(name)
BuildUSBStack(name)
if name == "rpipicow":
BuildCountry(name)
BuildIPStack(name)
if name == "generic":
BuildBoot(name)
BuildUploadMethodMenu(name)
MakeBoardJSON(name, vendor_name, product_name, vid, pid, pwr, boarddefine, flashsizemb, boot2, extra)
global pkgjson
thisbrd = {}
@@ -324,6 +319,9 @@ BuildGlobalMenuList()
MakeBoard("rpipico", "Raspberry Pi", "Pico", "0x2e8a", "0x000a", 250, "RASPBERRY_PI_PICO", 2, "boot2_w25q080_2_padded_checksum")
MakeBoard("rpipicow", "Raspberry Pi", "Pico W", "0x2e8a", "0xf00a", 250, "RASPBERRY_PI_PICO_W", 2, "boot2_w25q080_2_padded_checksum")
# 0xCB
MakeBoard("0xcb_helios", "0xCB", "Helios", "0x1209", "0xCB74", 500, "0XCB_HELIOS", 16, "boot2_w25q080_2_padded_checksum")
# Adafruit
MakeBoard("adafruit_feather", "Adafruit", "Feather RP2040", "0x239a", "0x80f1", 250, "ADAFRUIT_FEATHER_RP2040", 8, "boot2_w25x10cl_4_padded_checksum")
MakeBoard("adafruit_feather_scorpio", "Adafruit", "Feather RP2040 SCORPIO", "0x239a", "0x8121", 250, "ADAFRUIT_FEATHER_RP2040_SCORPIO", 8, "boot2_w25q080_2_padded_checksum")
@@ -347,9 +345,6 @@ MakeBoard("cytron_maker_pi_rp2040", "Cytron", "Maker Pi RP2040", "0x2e8a", "0x10
# DatanoiseTV
MakeBoard("datanoisetv_picoadk", "DatanoiseTV", "PicoADK", "0x2e8a", "0x000a", 250, "DATANOISETV_PICOADK", 2, "boot2_w25q080_2_padded_checksum")
# Degz
MakeBoard("degz_mizu", "Degz", "Mizu", "0x2e8a", "0x000a", 250, "DEGZ_MIZU", 8, "boot2_generic_03h_4_padded_checksum")
# DeRuiLab
MakeBoard("flyboard2040_core", "DeRuiLab", "FlyBoard2040Core", "0x2e8a", "0x008a", 500, "FLYBOARD2040_CORE", 4, "boot2_w25q080_2_padded_checksum")
@@ -377,6 +372,9 @@ MakeBoard("ilabs_rpico32", "iLabs", "RPICO32", "0x2e8a", "0x1010", 250, "ILABS_2
MakeBoard("melopero_cookie_rp2040", "Melopero", "Cookie RP2040", "0x2e8a", "0x1011", 250, "MELOPERO_COOKIE_RP2040", 8, "boot2_w25q080_2_padded_checksum")
MakeBoard("melopero_shake_rp2040", "Melopero", "Shake RP2040", "0x2e8a", "0x1005", 250, "MELOPERO_SHAKE_RP2040", 16, "boot2_w25q080_2_padded_checksum")
# nullbits
MakeBoard("nullbits_bit_c_pro", "nullbits", "Bit-C PRO", "0x2e8a", "0x6e61", 500, "NULLBITS_BIT_C_PRO", 4, "boot2_w25x10cl_4_padded_checksum")
# Pimoroni
MakeBoard("pimoroni_pga2040", "Pimoroni", "PGA2040", "0x2e8a", "0x1008", 250, "PIMORONI_PGA2040", 8, "boot2_w25q64jv_4_padded_checksum")
@@ -393,6 +391,12 @@ MakeBoard("upesy_rp2040_devkit", "uPesy", "RP2040 DevKit", "0x2e8a", "0x1007", 2
# Seeed
MakeBoard("seeed_xiao_rp2040", "Seeed", "XIAO RP2040", "0x2e8a", "0x000a", 250, "SEEED_XIAO_RP2040", 2, "boot2_w25q080_2_padded_checksum")
# VCC-GND YD-2040 - Use generic SPI/4 because boards seem to come with varied flash modules but same name
MakeBoard('vccgnd_yd_rp2040', "VCC-GND", "YD RP2040", "0x2e8a", "0x800a", 500, "YD_RP2040", 16, "boot2_generic_03h_4_padded_checksum")
# Viyalab
MakeBoard("viyalab_mizu", "Viyalab", "Mizu RP2040", "0x2e8a", "0x000a", 250, "VIYALAB_MIZU_RP2040", 8, "boot2_generic_03h_4_padded_checksum")
# Waveshare
MakeBoard("waveshare_rp2040_zero", "Waveshare", "RP2040 Zero", "0x2e8a", "0x0003", 500, "WAVESHARE_RP2040_ZERO", 2, "boot2_w25q16jvxq_4_padded_checksum")
MakeBoard("waveshare_rp2040_one", "Waveshare", "RP2040 One", "0x2e8a", "0x103a", 500, "WAVESHARE_RP2040_ONE", 4, "boot2_w25q16jvxq_4_padded_checksum")
@@ -400,6 +404,7 @@ MakeBoard("waveshare_rp2040_plus_4mb", "Waveshare", "RP2040 Plus 4MB", "0x2e8a",
MakeBoard("waveshare_rp2040_plus_16mb", "Waveshare", "RP2040 Plus 16MB", "0x2e8a", "0x1020", 500, "WAVESHARE_RP2040_PLUS", 16, "boot2_w25q080_2_padded_checksum")
MakeBoard("waveshare_rp2040_lcd_0_96", "Waveshare", "RP2040 LCD 0.96", "0x2e8a", "0x1021", 500, "WAVESHARE_RP2040_LCD_0_96", 2, "boot2_w25q16jvxq_4_padded_checksum")
MakeBoard("waveshare_rp2040_lcd_1_28", "Waveshare", "RP2040 LCD 1.28", "0x2e8a", "0x1039", 500, "WAVESHARE_RP2040_LCD_1_28", 2, "boot2_w25q16jvxq_4_padded_checksum")
# WIZnet
MakeBoard("wiznet_5100s_evb_pico", "WIZnet", "W5100S-EVB-Pico", "0x2e8a", "0x1027", 250, "WIZNET_5100S_EVB_PICO", 2, "boot2_w25q080_2_padded_checksum")
MakeBoard("wiznet_wizfi360_evb_pico", "WIZnet", "WizFi360-EVB-Pico", "0x2e8a", "0x1028", 250, "WIZNET_WIZFI360_EVB_PICO", 2, "boot2_w25q080_2_padded_checksum")
+1
View File
@@ -54,6 +54,7 @@ def scanner():
scannerGo = True
def main():
global scannerGo
while True:
cmdline = input()
cmd = cmdline.split()[0]
+41
View File
@@ -0,0 +1,41 @@
#pragma once
// Pin definitions taken from: https://raw.githubusercontent.com/0xCB-dev/0xCB-Helios/main/rev1.0/helios.webp
// LEDs
#define PIN_LED (17u)
// Serial
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
// Not pinned out
#define PIN_SERIAL2_TX (31u)
#define PIN_SERIAL2_RX (31u)
// SPI
#define PIN_SPI0_MISO (20u)
#define PIN_SPI0_MOSI (23u)
#define PIN_SPI0_SCK (22u)
#define PIN_SPI0_SS (21u)
// Not pinned out
#define PIN_SPI1_MISO (31u)
#define PIN_SPI1_MOSI (31u)
#define PIN_SPI1_SCK (31u)
#define PIN_SPI1_SS (31u)
// Not pinned out
#define PIN_WIRE0_SDA (31u)
#define PIN_WIRE0_SCL (31u)
// Wire
#define PIN_WIRE1_SDA (2u)
#define PIN_WIRE1_SCL (3u)
#define SERIAL_HOWMANY (1u)
#define SPI_HOWMANY (1u)
#define WIRE_HOWMANY (1u)
#define PIN_NEOPIXEL (25u)
#include "../generic/common.h"
@@ -0,0 +1,37 @@
#pragma once
// Taken from pinout at https://nullbits.co/static/img/BIt-C_PRO_pinout.png
// LEDs
#define PIN_LED (18u)
// UARTs
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
#define PIN_SERIAL2_TX (8u)
#define PIN_SERIAL2_RX (9u)
// SPI
#define PIN_SPI0_MISO (20u)
#define PIN_SPI0_MOSI (23u)
#define PIN_SPI0_SCK (22u)
#define PIN_SPI0_SS (21u)
#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (11u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (13u)
// Wire
#define PIN_WIRE0_SDA (2u)
#define PIN_WIRE0_SCL (3u)
#define PIN_WIRE1_SDA (4u)
#define PIN_WIRE1_SCL (5u)
#define SERIAL_HOWMANY (3u)
#define SPI_HOWMANY (2u)
#define WIRE_HOWMANY (2u)
#include "../generic/common.h"