Compare commits

...
17 Commits
Author SHA1 Message Date
Earle F. Philhower, III c670f66140 Update version 2024-02-16 13:11:02 -08:00
Earle F. Philhower, III a09ce0d8d0 Update Windows Picotool blob pointers (#2009)
Fixes #2008
2024-02-16 11:38:39 -08:00
Earle F. Philhower, III 795968a8e0 Clean up WIFI local variable MAC size (#2006)
MACs are 6-bytes long, not 8.
2024-02-14 12:17:09 -08:00
Earle F. Philhower, III 01ab02d02a Fix ESPHost WiFi connect without a specified BSSID (#2007)
See https://github.com/earlephilhower/arduino-pico/pull/2001#issuecomment-1944461469
2024-02-14 12:00:06 -08:00
Earle F. Philhower, III 7e73e0b5b4 Can't call get_rand_64 under FreeRTOS (#2004)
Remove the HW random generator call while initting LWIP to avoid the SDK
looping forver due to FreeRTOS exception/timer interrupts.
2024-02-13 12:08:33 -08:00
Earle F. Philhower, III 91c007eb8f Update version 2024-02-12 10:38:24 -08:00
ardnew b29f6b922f Update README.md (#1999)
The `Picoprobe` example showing how to upload to Ubuntu is invalid because Ubuntu does not create or assign users to a `users` group (for many major releases, now). 

The reason the example worked is because the permissions were applied globally, rendering the `GROUP=users` assignment in the rule irrelevant. Hence, this assignment has been dropped.  

The `pico-debug` example has been updated similarly, but it uses a proper group-level rule, and Ubuntu does still use group `plugdev`. 

The reader thus has two good examples of creating `udev` rules.
2024-02-12 10:27:52 -08:00
Earle F. Philhower, III 40e52f84b8 Fix WiFiMulti and ESPhost STA connection w/BSSID (#2001)
WiFiMulti specifies a specific BSSID, in addition to the AP name and
password.  In the WiFi core the BSSID is stored as the raw 6-byte MAC
address, but the ESPHostedFG firmware expects a formatted C-String
(i.e. "ab:cd:ef:01:02:03" instead of {0xab, 0xcd, 0xef, 1, 2, 3})

Convert the raw bytes to the string format expected in the ESP FW.
2024-02-12 10:17:36 -08:00
Earle F. Philhower, III 972b7f53be Fix warning in lwip_ESPHost, add to styler (#1998) 2024-02-11 11:51:16 -08:00
Kevin Witteveen fc894fba0e PWMAudio low bitrate whine fix (DMA pacing timer) (#1996) 2024-02-10 09:17:37 -08:00
Earle F. Philhower, III 929ee98a6c Make W5100 example run on Wiznet w/no changes (#1994)
Use the #define board name to identify when building for the
WIZnet W5100s-EVB-Pico and assign the proper pins and IRQs.
2024-02-09 14:06:28 -08:00
Earle F. Philhower, III 88ccf0c256 Undo FreeRTOS idleOtherCore changes (#1992)
Fixes #1991
2024-02-09 09:46:30 -08:00
Terry Phillips 874b41f549 Update wire.rst (#1990)
Correct buffer size to match Wire.h
2024-02-06 16:27:08 -08:00
LinusHeu fcd47fe170 Update ide.rst (#1989)
Remove outdated(?) info
2024-02-06 15:43:14 -08:00
Earle F. Philhower, III 842ec245ac Add W5100, W5500, and ECN28J60 interrupt-driven mode (#1986)
No polling needed and massively reduces latency by using the GPIO interrupt to
signal the Pico to read a received packet.  Also drops CPU load when no packets
are incoming.
2024-02-06 14:15:37 -08:00
Earle F. Philhower, III a41618fa87 Make Python3 re.split() use a r-string (#1985)
Fixes #1983
2024-02-06 09:49:45 -08:00
Earle F. Philhower, III c095fce5b2 More GH action updates (#1980) 2024-02-02 09:24:22 -08:00
32 changed files with 389 additions and 127 deletions
+4 -4
View File
@@ -9,21 +9,21 @@ jobs:
name: Update master JSON file
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: true
- name: Cache pip
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
# - name: Cache PlatformIO
# uses: actions/cache@v3
# uses: actions/cache@v4
# with:
# path: ~/.platformio
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
+2 -2
View File
@@ -15,11 +15,11 @@ jobs:
name: Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Build package JSON
+10 -4
View File
@@ -202,11 +202,14 @@ Under Windows a local admin user should be able to access the Picoprobe port aut
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
````
echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", GROUP="users", MODE="0666"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="0666"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
sudo udevadm control --reload
sudo udevadm trigger -w -s usb
````
The first line creates a file with the USB vendor and ID of the Picoprobe and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
The first line creates a device file in `/dev` matching the USB vendor and product ID of the Picoprobe, and it enables global read+write permissions. The second line causes `udev` to load this new rule. The third line requests the kernel generate "device change" events that will cause our new `udev` rule to run.
If for some reason the device file does not appear, manually unplug and re-plug the USB connection and check again. The output from `dmesg` can reveal useful diagnostics if the device file remains absent.
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
@@ -215,13 +218,16 @@ Once Picoprobe permissions are set up properly, then select the board "Raspberry
Under Windows and macOS, any user should be able to access pico-debug automatically, but under Linux `udev` must be told about the device and to allow normal users access.
To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes which use `udev`):
To set up group-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes which use `udev`):
````
echo 'ATTRS{product}=="*CMSIS-DAP*", MODE="664", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-CMSIS-DAP.rules
sudo udevadm control --reload
sudo udevadm trigger -w -s usb
````
The first line creates a file that recognizes all CMSIS-DAP adapters and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
The first line creates a device file in `/dev` that matches all CMSIS-DAP adapters, and it enables read+write permissions for members of the `plugdev` group. The second line causes `udev` to load this new rule. The third line requests the kernel generate "device change" events that will cause our new `udev` rule to run.
If for some reason the device file does not appear, manually unplug and re-plug the USB connection and check again. The output from `dmesg` can reveal useful diagnostics if the device file remains absent.
Once CMSIS-DAP permissions are set up properly, then select the board "Raspberry Pi Pico (pico-debug)" in the Tools menu.
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 3
#define ARDUINO_PICO_MINOR 7
#define ARDUINO_PICO_REVISION 0
#define ARDUINO_PICO_VERSION_STR "3.7.0"
#define ARDUINO_PICO_REVISION 2
#define ARDUINO_PICO_VERSION_STR "3.7.2"
+16 -6
View File
@@ -33,12 +33,17 @@
extern void ethernet_arch_lwip_begin() __attribute__((weak));
extern void ethernet_arch_lwip_end() __attribute__((weak));
extern void ethernet_arch_lwip_gpio_mask() __attribute__((weak));
extern void ethernet_arch_lwip_gpio_unmask() __attribute__((weak));
auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?)
class LWIPMutex {
public:
LWIPMutex() {
if (ethernet_arch_lwip_gpio_mask) {
ethernet_arch_lwip_gpio_mask();
}
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (rp2040.isPicoW()) {
cyw43_arch_lwip_begin();
@@ -56,13 +61,18 @@ public:
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (rp2040.isPicoW()) {
cyw43_arch_lwip_end();
return;
} else {
#endif
if (ethernet_arch_lwip_end) {
ethernet_arch_lwip_end();
} else {
recursive_mutex_exit(&__lwipMutex);
}
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
}
#endif
if (ethernet_arch_lwip_end) {
ethernet_arch_lwip_end();
} else {
recursive_mutex_exit(&__lwipMutex);
if (ethernet_arch_lwip_gpio_unmask) {
ethernet_arch_lwip_gpio_unmask();
}
}
};
@@ -79,7 +89,7 @@ extern "C" {
extern void __real_lwip_init();
void __wrap_lwip_init() {
if (!_lwip_rng) {
_lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(get_rand_64());
_lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros() * rp2040.getCycleCount());
__real_lwip_init();
}
}
+2 -2
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'3.7.0'
version = u'3.7.2'
# The full version, including alpha/beta/rc tags.
release = u'3.7.0'
release = u'3.7.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+15 -2
View File
@@ -86,6 +86,19 @@ Pico may not have enough time to service the Ethernet port before the timer fire
leading to a lock up and hang.
Using Interrupt-Driven Handling
-------------------------------
The WizNet and ENC28J60 devices support generating an interrupt when a packet is received,
removing the need for polling and decreasing latency. Simply specify the SPI object to use and the
interrupt pin when instantiating the Ethernet object:
.. code:: cpp
#include <W5100lwIP.h>
Wiznet5100lwIP eth(SS /* Chip Select*/, SPI /* SPI interface */, 17 /* Interrupt GPIO */ );
Adjusting SPI Speed
-------------------
@@ -114,12 +127,12 @@ For example, to set the W5500 to use a 30MHZ clock:
Using the WIZnet W5100S-EVB-Pico
--------------------------------
You can use the onboard Ethernet chip with these drivers by utilizing the following options:
You can use the onboard Ethernet chip with these drivers, in interrupt mode, by utilizing the following options:
.. code:: cpp
#include <W5100lwIP.h>
Wiznet5100lwIP eth(17); // Note chip select is **17**
Wiznet5100lwIP eth(17, SPI, 21); // Note chip select is **17**
void setup() {
// Set SPI to the onboard Wiznet chip
+3 -7
View File
@@ -1,15 +1,11 @@
IDE Menus
=========
Model
Board
-----
Use the boards menu to select your model of RP2040 board. There will be two
options: `Boardname` and `Boardname (Picoprobe)`. If you want to use a
Picoprobe to upload your sketches and not the default automatic UF2 upload,
use the `(Picoprobe)` option, otherwise use the normal name. No functional
or code changes are done because of this.
Use the boards menu to select your model of RP2040 board.
There is also a `Generic` board which allows you to individually select
There is also a `Generic RP2040` board which allows you to individually select
things such as flash size or boot2 flash type. Use this if your board isn't
yet fully supported and isn't working with the normal `Raspberry Pi Pico`
option.
+1 -1
View File
@@ -20,7 +20,7 @@ diagram for your board, or it won't work.
Other than that, the API is compatible with the Arduino standard.
Both master and slave operation are supported.
Master transmissions are buffered (up to 128 bytes) and only performed
Master transmissions are buffered (up to 256 bytes) and only performed
on ``endTransmission``, as is standard with modern Arduino Wire implementations.
For more detailed information, check the `Arduino Wire documentation <https://www.arduino.cc/en/reference/wire>`_ .
+3 -3
View File
@@ -165,14 +165,14 @@ static void __no_inline_not_in_flash_func(IdleThisCore)(void *param) {
(void) param;
while (true) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
portDISABLE_INTERRUPTS();
vTaskPreemptionDisable(nullptr);
portDISABLE_INTERRUPTS();
__otherCoreIdled = true;
while (__otherCoreIdled) {
/* noop */
}
vTaskPreemptionEnable(nullptr);
portENABLE_INTERRUPTS();
vTaskPreemptionEnable(nullptr);
}
}
@@ -188,9 +188,9 @@ extern "C" void __no_inline_not_in_flash_func(__freertos_idle_other_core)() {
extern "C" void __no_inline_not_in_flash_func(__freertos_resume_other_core)() {
__otherCoreIdled = false;
portENABLE_INTERRUPTS();
xTaskResumeAll();
vTaskPreemptionEnable(nullptr);
portENABLE_INTERRUPTS();
}
+73 -3
View File
@@ -32,6 +32,8 @@ PWMAudio::PWMAudio(pin_size_t pin, bool stereo) {
_buffers = 8;
_bufferWords = 0;
_stereo = stereo;
_sampleRate = 48000;
_pacer = -1;
}
PWMAudio::~PWMAudio() {
@@ -63,7 +65,7 @@ bool PWMAudio::setStereo(bool stereo) {
return true;
}
bool PWMAudio::setFrequency(int newFreq) {
bool PWMAudio::setPWMFrequency(int newFreq) {
_freq = newFreq;
// Figure out the scale factor for PWM values
@@ -92,6 +94,17 @@ bool PWMAudio::setFrequency(int newFreq) {
return true;
}
bool PWMAudio::setFrequency(int frequency) {
if (_pacer < 0) {
return false;
}
uint16_t _pacer_D, _pacer_N;
/*Flip fraction(N for D, D for N) because we are using it as sys_clk * fraction(mechanic of dma_timer_set_fraction) for smaller than sys_clk values*/
find_pacer_fraction(frequency, &_pacer_D, &_pacer_N);
dma_timer_set_fraction(_pacer, _pacer_N, _pacer_D);
return true;
}
void PWMAudio::onTransmit(void(*fn)(void)) {
_cb = fn;
if (_running) {
@@ -117,12 +130,25 @@ bool PWMAudio::begin() {
_bufferWords = 16;
}
setFrequency(_freq);
setPWMFrequency(_freq);
/*Calculate and set the DMA pacer timer. This timer will pull data on a fixed sample rate. So the actual PWM frequency can be higher or lower.*/
_pacer = dma_claim_unused_timer(false);
/*When no unused timer is found, return*/
if (_pacer < 0) {
return false;
}
uint16_t _pacer_D = 0;
uint16_t _pacer_N = 0;
/*Flip fraction(N for D, D for N) because we are using it as sys_clk * fraction(mechanic of dma_timer_set_fraction) for smaller than sys_clk values*/
find_pacer_fraction(_sampleRate, &_pacer_D, &_pacer_N);
dma_timer_set_fraction(_pacer, _pacer_N, _pacer_D);
int _pacer_dreq = dma_get_timer_dreq(_pacer);
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);
if (!_arb->begin(pwm_get_dreq(pwm_gpio_to_slice_num(_pin)), (volatile void*)ccAddr)) {
if (!_arb->begin(_pacer_dreq, (volatile void*)ccAddr)) {
_running = false;
delete _arb;
_arb = nullptr;
@@ -143,6 +169,9 @@ void PWMAudio::end() {
}
delete _arb;
_arb = nullptr;
dma_timer_unclaim(_pacer);
_pacer = -1;
}
}
@@ -219,3 +248,44 @@ size_t PWMAudio::write(const uint8_t *buffer, size_t size) {
}
return writtenSize;
}
void PWMAudio::find_pacer_fraction(int target, uint16_t *numerator, uint16_t *denominator) {
const uint16_t max = 0xFFFF;
/*Cache last results so we dont have to recalculate*/
static int last_target;
static uint16_t bestNum;
static uint16_t bestDenom;
/*Check if we can load the previous values*/
if (target == last_target) {
*numerator = bestNum;
*denominator = bestDenom;
return;
}
float targetRatio = (float)F_CPU / target;
float lowestError = HUGE_VALF;
for (uint16_t denom = 1; denom < max; denom++) {
uint16_t num = (int)((targetRatio * denom) + 0.5f); /*Calculate numerator, rounding to nearest integer*/
/*Check if numerator is within bounds*/
if (num > 0 && num < max) {
float actualRatio = (float)num / denom;
float error = fabsf(actualRatio - targetRatio);
if (error < lowestError) {
bestNum = num;
bestDenom = denom;
lowestError = error;
if (error == 0) {
break;
}
}
}
}
last_target = target;
*numerator = bestNum;
*denominator = bestDenom;
}
+17 -2
View File
@@ -29,12 +29,21 @@ public:
virtual ~PWMAudio();
bool setBuffers(size_t buffers, size_t bufferWords);
bool setFrequency(int newFreq);
/*Sets the frequency of the PWM in hz*/
bool setPWMFrequency(int newFreq);
/*Sets the sample rate frequency in hz*/
bool setFrequency(int frequency);
bool setPin(pin_size_t pin);
bool setStereo(bool stereo = true);
bool begin(long sampleRate) {
setFrequency(sampleRate);
_sampleRate = sampleRate;
return begin();
}
bool begin(long sampleRate, long PWMfrequency) {
setPWMFrequency(PWMfrequency);
_sampleRate = sampleRate;
return begin();
}
@@ -70,6 +79,9 @@ private:
bool _stereo;
int _freq;
int _sampleRate;
int _pacer;
size_t _buffers;
size_t _bufferWords;
@@ -84,4 +96,7 @@ private:
void (*_cb)();
AudioBufferManager *_arb;
/*An accurate but brute force method to find 16bit numerator and denominator.*/
void find_pacer_fraction(int target, uint16_t *numerator, uint16_t *denominator);
};
+2 -2
View File
@@ -154,7 +154,7 @@ public:
}
String softAPmacAddress(void) {
uint8_t mac[8];
uint8_t mac[6];
macAddress(mac);
char buff[32];
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@@ -240,7 +240,7 @@ public:
*/
uint8_t* macAddress(uint8_t* mac);
String macAddress(void) {
uint8_t mac[8];
uint8_t mac[6];
macAddress(mac);
char buff[32];
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+14 -14
View File
@@ -1,22 +1,22 @@
/*
WiFi <-> LWIP for ESPHost library in RP2040 Core
WiFi <-> LWIP for ESPHost library in RP2040 Core
Copyright (c) 2024 Juraj Andrassy
Copyright (c) 2024 Juraj Andrassy
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 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.
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
*/
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 "ESPHost.h"
#include "CEspControl.h"
+1 -1
View File
@@ -16,7 +16,7 @@
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
+20 -11
View File
@@ -51,10 +51,10 @@ void ESPHostLwIP::setSSID(const char *ssid) {
}
void ESPHostLwIP::setBSSID(const uint8_t *bssid) {
if (bssid == nullptr) {
if (bssid == nullptr || !(bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])) {
ap.bssid[0] = 0;
} else {
memcpy(ap.bssid, bssid, sizeof(ap.bssid));
snprintf((char *)ap.bssid, sizeof(ap.bssid), "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
}
}
@@ -95,14 +95,16 @@ int ESPHostLwIP::disconnectEventCb(CCtrlMsgWrapper *resp) {
}
bool ESPHostLwIP::initHW() {
if (wifiHwInitialized)
if (wifiHwInitialized) {
return true;
}
instance = this;
CEspControl::getInstance().listenForStationDisconnectEvent(disconnectEventCb);
CEspControl::getInstance().listenForInitEvent(initEventCb);
if (CEspControl::getInstance().initSpiDriver() != 0)
if (CEspControl::getInstance().initSpiDriver() != 0) {
return false;
}
uint32_t start = millis();
while (!wifiHwInitialized && (millis() - start < timeout)) {
@@ -117,8 +119,9 @@ bool ESPHostLwIP::initHW() {
}
bool ESPHostLwIP::begin() {
if (!initHW())
if (!initHW()) {
return false;
}
ethernet_arch_lwip_begin();
if (!apMode) {
CEspControl::getInstance().setWifiMode(WIFI_MODE_STA);
@@ -131,7 +134,7 @@ bool ESPHostLwIP::begin() {
} else {
CEspControl::getInstance().setWifiMode(WIFI_MODE_AP);
if (softAP.channel == 0 || softAP.channel > MAX_CHNL_NO) {
softAP.channel = 1;
softAP.channel = 1;
}
softAP.max_connections = MAX_SOFTAP_CONNECTION_DEF;
softAP.encryption_mode = softAP.pwd[0] == 0 ? WIFI_AUTH_OPEN : WIFI_AUTH_WPA_WPA2_PSK;
@@ -198,8 +201,9 @@ uint8_t ESPHostLwIP::status() {
}
uint8_t* ESPHostLwIP::macAddress(bool apMode, uint8_t *mac) {
if (!initHW())
if (!initHW()) {
return mac;
}
WifiMac_t MAC;
MAC.mode = apMode ? WIFI_MODE_AP : WIFI_MODE_STA;
ethernet_arch_lwip_begin();
@@ -220,8 +224,9 @@ int ESPHostLwIP::channel() {
}
int32_t ESPHostLwIP::RSSI() {
if (!joined)
if (!joined) {
return 0;
}
ethernet_arch_lwip_begin();
CEspControl::getInstance().getAccessPointConfig(ap);
ethernet_arch_lwip_end();
@@ -254,15 +259,18 @@ uint8_t ESPHostLwIP::encryptionType() {
}
int8_t ESPHostLwIP::scanNetworks(bool async) {
(void) async;
accessPoints.clear();
if (!initHW())
if (!initHW()) {
return -1;
}
ethernet_arch_lwip_begin();
int res = CEspControl::getInstance().getAccessPointScanList(accessPoints);
ethernet_arch_lwip_end();
wifiStatus = WL_SCAN_COMPLETED;
if (res != ESP_CONTROL_OK)
if (res != ESP_CONTROL_OK) {
return -1;
}
return accessPoints.size();
}
@@ -310,8 +318,9 @@ int32_t ESPHostLwIP::RSSI(uint8_t networkItem) {
}
void ESPHostLwIP::lowPowerMode() {
if (!initHW())
if (!initHW()) {
return;
}
ethernet_arch_lwip_begin();
CEspControl::getInstance().setPowerSaveMode(1);
ethernet_arch_lwip_end();
+1 -1
View File
@@ -16,7 +16,7 @@
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
@@ -72,6 +72,45 @@ void __removeEthernetPacketHandler(int id) {
ethernet_arch_lwip_end();
}
#define GPIOSTACKSIZE 8
static uint32_t gpioMaskStack[GPIOSTACKSIZE][4];
static uint32_t gpioMask[4] = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
void ethernet_arch_lwip_gpio_mask() {
noInterrupts();
memmove(gpioMaskStack[1], gpioMaskStack[0], 4 * sizeof(uint32_t) * (GPIOSTACKSIZE - 1)); // Push down the stack
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
for (int i = 0; i < 4; i++) {
gpioMaskStack[0][i] = irq_ctrl_base->inte[i];
irq_ctrl_base->inte[i] = irq_ctrl_base->inte[i] & gpioMask[i];
}
interrupts();
}
void ethernet_arch_lwip_gpio_unmask() {
noInterrupts();
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
for (int i = 0; i < 4; i++) {
irq_ctrl_base->inte[i] = gpioMaskStack[0][i];
}
memmove(gpioMaskStack[0], gpioMaskStack[1], 4 * sizeof(uint32_t) * (GPIOSTACKSIZE - 1)); // Pop up the stack
interrupts();
}
// To be called after IRQ is set, so we can just rad from the IOREG instead of duplicating the calculation
void __addEthernetGPIO(int pin) {
int idx = pin / 8;
int off = (pin % 8) * 4;
gpioMask[idx] &= ~(0xf << off);
}
void __removeEthernetGPIO(int pin) {
int idx = pin / 8;
int off = (pin % 8) * 4;
gpioMask[idx] |= 0xf << off;
}
static volatile bool _dns_lookup_pending = false;
static void _dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
@@ -134,6 +173,7 @@ static uint32_t _pollingPeriod = 20;
static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) {
assert(worker == &ethernet_timeout_worker);
__ethernet_timeout_reached_calls++;
ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us
for (auto handlePacket : _handlePacketList) {
handlePacket.second();
}
@@ -144,6 +184,7 @@ static void ethernet_timeout_reached(__unused async_context_t *context, __unused
#else
sys_check_timeouts();
#endif
ethernet_arch_lwip_gpio_unmask();
}
static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker) {
@@ -27,6 +27,11 @@
void ethernet_arch_lwip_begin() __attribute__((weak));
void ethernet_arch_lwip_end() __attribute__((weak));
void ethernet_arch_lwip_gpio_mask() __attribute__((weak));
void ethernet_arch_lwip_gpio_unmask() __attribute__((weak));
void __addEthernetGPIO(int pin);
void __removeEthernetGPIO(int pin);
// Internal Ethernet helper functions
void __startEthernetContext();
+24 -3
View File
@@ -144,6 +144,7 @@ public:
return _packetsSent;
}
// ESP8266WiFi API compatibility
wl_status_t status();
@@ -156,6 +157,7 @@ protected:
static err_t netif_init_s(netif* netif);
static err_t linkoutput_s(netif* netif, struct pbuf* p);
static void netif_status_callback_s(netif* netif);
static void _irq(void *param);
public:
// called on a regular basis or on interrupt
err_t handlePackets();
@@ -358,7 +360,9 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
return false;
}
_phID = __addEthernetPacketHandler([this] { this->handlePackets(); });
if (_intrPin < 0) {
_phID = __addEthernetPacketHandler([this] { this->handlePackets(); });
}
if (localIP().v4() == 0) {
// IP not set, starting DHCP
@@ -393,7 +397,11 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
if (_intrPin >= 0) {
if (RawDev::interruptIsPossible()) {
// attachInterrupt(_intrPin, [&]() { this->handlePackets(); }, FALLING);
noInterrupts(); // Ensure this is atomically set up
pinMode(_intrPin, INPUT);
attachInterruptParam(_intrPin, _irq, LOW, (void*)this);
__addEthernetGPIO(_intrPin);
interrupts();
} else {
::printf((PGM_P)F(
"lwIP_Intf: Interrupt not implemented yet, enabling transparent polling\r\n"));
@@ -406,7 +414,12 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
template<class RawDev>
void LwipIntfDev<RawDev>::end() {
__removeEthernetPacketHandler(_phID);
if (_intrPin < 0) {
__removeEthernetPacketHandler(_phID);
} else {
detachInterrupt(_intrPin);
__removeEthernetGPIO(_intrPin);
}
RawDev::end();
@@ -415,6 +428,14 @@ void LwipIntfDev<RawDev>::end() {
_started = false;
}
template<class RawDev>
void LwipIntfDev<RawDev>::_irq(void *param) {
LwipIntfDev *d = static_cast<LwipIntfDev*>(param);
ethernet_arch_lwip_begin();
d->handlePackets();
sys_check_timeouts();
ethernet_arch_lwip_end();
}
template<class RawDev>
wl_status_t LwipIntfDev<RawDev>::status() {
@@ -69,6 +69,9 @@
#define ECON2_AUTOINC 0x80
#define ECON2_PKTDEC 0x40
#define EIE_PKTIE 0x40
#define EIE_INTIE 0x80
#define EIR_TXIF 0x08
#define ERXTX_BANK 0x00
@@ -153,8 +156,7 @@
// The ENC28J60 SPI Interface supports clock speeds up to 20 MHz
static const SPISettings spiSettings(20000000, MSBFIRST, SPI_MODE0);
ENC28J60::ENC28J60(int8_t cs, SPIClass& spi, int8_t intr) : _bank(ERXTX_BANK), _cs(cs), _spi(spi) {
(void)intr;
ENC28J60::ENC28J60(int8_t cs, SPIClass& spi, int8_t intr) : _bank(ERXTX_BANK), _cs(cs), _intr(intr), _spi(spi) {
}
void ENC28J60::enc28j60_arch_spi_select(void) {
@@ -488,6 +490,12 @@ bool ENC28J60::reset(void) {
/* Turn on autoincrement for buffer access */
setregbitfield(ECON2, ECON2_AUTOINC);
/* Enable interrupt on packet receive if desired */
if (_intr >= 0) {
setregbitfield(EIE, EIE_PKTIE);
setregbitfield(EIE, EIE_INTIE);
}
/* Turn on reception */
writereg(ECON1, ECON1_RXEN);
@@ -511,6 +519,8 @@ bool ENC28J60::begin(const uint8_t* address, netif *net) {
uint16_t ENC28J60::sendFrame(const uint8_t* data, uint16_t datalen) {
uint16_t dataend;
ethernet_arch_lwip_gpio_mask(); // So we don't fire an IRQ and interrupt the send w/a receive!
/*
1. Appropriately program the ETXST pointer to point to an unused
location in memory. It will point to the per packet control
@@ -582,6 +592,8 @@ uint16_t ENC28J60::sendFrame(const uint8_t* data, uint16_t datalen) {
}
#endif
ethernet_arch_lwip_gpio_unmask();
// sent_packets++;
// PRINTF("enc28j60: sent_packets %d\n", sent_packets);
return datalen;
@@ -99,7 +99,7 @@ public:
netif *_netif;
protected:
static constexpr bool interruptIsPossible() {
return false;
return true;
}
/**
@@ -154,6 +154,7 @@ private:
uint8_t _bank;
int8_t _cs;
int8_t _intr;
SPIClass& _spi;
const uint8_t* _localMac;
@@ -8,14 +8,21 @@
const char* host = "djxmmx.net";
const uint16_t port = 17;
#ifdef ARDUINO_WIZNET_5100S_EVB_PICO
// To use Interrupt-driven mode, pass in an SPI object and an IRQ pin like so:
Wiznet5100lwIP eth(17, SPI, 21);
#else
Wiznet5100lwIP eth(1 /* chip select */);
#endif
void setup() {
#ifndef ARDUINO_WIZNET_5100S_EVB_PICO
// Set up SPI pinout to match your HW
SPI.setRX(0);
SPI.setCS(1);
SPI.setSCK(2);
SPI.setTX(3);
#endif
Serial.begin(115200);
delay(5000);
+14 -19
View File
@@ -34,6 +34,7 @@
#include <SPI.h>
#include "w5100.h"
#include <LwipEthernet.h>
uint8_t Wiznet5100::wizchip_read(uint16_t address) {
uint8_t ret;
@@ -178,8 +179,7 @@ void Wiznet5100::wizchip_sw_reset() {
setSHAR(_mac_address);
}
Wiznet5100::Wiznet5100(int8_t cs, SPIClass& spi, int8_t intr) : _spi(spi), _cs(cs) {
(void)intr;
Wiznet5100::Wiznet5100(int8_t cs, SPIClass& spi, int8_t intr) : _spi(spi), _cs(cs), _intr(intr) {
}
bool Wiznet5100::begin(const uint8_t* mac_address, netif *net) {
@@ -189,13 +189,6 @@ bool Wiznet5100::begin(const uint8_t* mac_address, netif *net) {
pinMode(_cs, OUTPUT);
wizchip_cs_deselect();
#if 0
_spi.begin();
_spi.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
_spi.setBitOrder(MSBFIRST);
_spi.setDataMode(SPI_MODE0);
#endif
wizchip_sw_reset();
// Set the size of the Rx and Tx buffers
@@ -213,6 +206,11 @@ bool Wiznet5100::begin(const uint8_t* mac_address, netif *net) {
return false;
}
if (_intr >= 0) {
setSn_IR(0xff); // Clear everything
setIMR(IM_IR0);
}
// Success
return true;
}
@@ -245,6 +243,8 @@ uint16_t Wiznet5100::readFrame(uint8_t* buffer, uint16_t bufsize) {
}
uint16_t Wiznet5100::readFrameSize() {
setSn_IR(Sn_IR_RECV);
uint16_t len = getSn_RX_RSR();
if (len == 0) {
@@ -273,25 +273,18 @@ uint16_t Wiznet5100::readFrameData(uint8_t* buffer, uint16_t framesize) {
wizchip_recv_data(buffer, framesize);
setSn_CR(Sn_CR_RECV);
#if 1
// let lwIP deal with mac address filtering
return framesize;
#else
// W5100 doesn't have any built-in MAC address filtering
if ((buffer[0] & 0x01) || memcmp(&buffer[0], _mac_address, 6) == 0) {
// Addressed to an Ethernet multicast address or our unicast address
return framesize;
} else {
return 0;
}
#endif
}
uint16_t Wiznet5100::sendFrame(const uint8_t* buf, uint16_t len) {
ethernet_arch_lwip_gpio_mask(); // So we don't fire an IRQ and interrupt the send w/a receive!
// Wait for space in the transmit buffer
while (1) {
uint16_t freesize = getSn_TX_FSR();
if (getSn_SR() == SOCK_CLOSED) {
ethernet_arch_lwip_gpio_unmask();
return -1;
}
if (len <= freesize) {
@@ -311,9 +304,11 @@ uint16_t Wiznet5100::sendFrame(const uint8_t* buf, uint16_t len) {
} else if (tmp & Sn_IR_TIMEOUT) {
setSn_IR(Sn_IR_TIMEOUT);
// There was a timeout
ethernet_arch_lwip_gpio_unmask();
return -1;
}
}
ethernet_arch_lwip_gpio_unmask();
return len;
}
+31 -1
View File
@@ -101,7 +101,7 @@ public:
netif *_netif;
protected:
static constexpr bool interruptIsPossible() {
return false;
return true;
}
/**
@@ -144,6 +144,7 @@ private:
SPIClass& _spi;
int8_t _cs;
int8_t _intr;
uint8_t _mac_address[6];
/**
@@ -308,6 +309,17 @@ private:
MR_IND = 0x01, ///< Indirect Bus Interface mode
};
/** Interrupt Mask register values */
enum {
IM_IR0 = 0x01, ///< Occurrence of Socket 0 Socket Interrupt Enable
IM_IR1 = 0x02, ///< Occurrence of Socket 1 Socket Interrupt Enable
IM_IR2 = 0x04, ///< Occurrence of Socket 2 Socket Interrupt Enable
IM_IR3 = 0x08, ///< Occurrence of Socket 3 Socket Interrupt Enable
IM_IR5 = 0x20, ///< PPPoE Close Enable
IM_IR6 = 0x40, ///< Destination unreachable Enable
IM_IR7 = 0x80, ///< IP Conflict Enable
};
/** Socket Mode Register values @ref Sn_MR */
enum {
Sn_MR_CLOSE = 0x00, ///< Unused socket
@@ -375,6 +387,24 @@ private:
return wizchip_read(MR);
}
/**
Set Interrupt Mask Register
@param (uint8_t)mr The value to be set.
@sa geIMR()
*/
inline void setIMR(uint8_t mode) {
wizchip_write(IMR, mode);
}
/**
Get Mode Register
@return uint8_t. The value of Mode register.
@sa setIMR()
*/
inline uint8_t getIMR() {
return wizchip_read(IMR);
}
/**
Set local MAC address
@param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6
+14 -20
View File
@@ -34,6 +34,7 @@
#include <SPI.h>
#include "w5500.h"
#include <LwipEthernet.h>
uint8_t Wiznet5500::wizchip_read(uint8_t block, uint16_t address) {
uint8_t ret;
@@ -238,8 +239,7 @@ int8_t Wiznet5500::wizphy_setphypmode(uint8_t pmode) {
return -1;
}
Wiznet5500::Wiznet5500(int8_t cs, SPIClass& spi, int8_t intr) : _spi(spi), _cs(cs) {
(void)intr;
Wiznet5500::Wiznet5500(int8_t cs, SPIClass& spi, int8_t intr) : _spi(spi), _cs(cs), _intr(intr) {
}
bool Wiznet5500::begin(const uint8_t* mac_address, netif *net) {
@@ -249,13 +249,6 @@ bool Wiznet5500::begin(const uint8_t* mac_address, netif *net) {
pinMode(_cs, OUTPUT);
wizchip_cs_deselect();
#if 0
_spi.begin();
_spi.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
_spi.setBitOrder(MSBFIRST);
_spi.setDataMode(SPI_MODE0);
#endif
wizchip_sw_reset();
// Use the full 16Kb of RAM for Socket 0
@@ -273,6 +266,11 @@ bool Wiznet5500::begin(const uint8_t* mac_address, netif *net) {
return false;
}
if (_intr >= 0) {
setSn_IR(0xff); // Clear everything
setSIMR(1);
}
// Success
return true;
}
@@ -305,6 +303,8 @@ uint16_t Wiznet5500::readFrame(uint8_t* buffer, uint16_t bufsize) {
}
uint16_t Wiznet5500::readFrameSize() {
setSn_IR(Sn_IR_RECV);
uint16_t len = getSn_RX_RSR();
if (len == 0) {
@@ -333,26 +333,18 @@ uint16_t Wiznet5500::readFrameData(uint8_t* buffer, uint16_t framesize) {
wizchip_recv_data(buffer, framesize);
setSn_CR(Sn_CR_RECV);
#if 1
// let lwIP deal with mac address filtering
return framesize;
#else
// Had problems with W5500 MAC address filtering (the Sn_MR_MFEN option)
// Do it in software instead:
if ((buffer[0] & 0x01) || memcmp(&buffer[0], _mac_address, 6) == 0) {
// Addressed to an Ethernet multicast address or our unicast address
return framesize;
} else {
return 0;
}
#endif
}
uint16_t Wiznet5500::sendFrame(const uint8_t* buf, uint16_t len) {
ethernet_arch_lwip_gpio_mask(); // So we don't fire an IRQ and interrupt the send w/a receive!
// Wait for space in the transmit buffer
while (1) {
uint16_t freesize = getSn_TX_FSR();
if (getSn_SR() == SOCK_CLOSED) {
ethernet_arch_lwip_gpio_unmask();
return -1;
}
if (len <= freesize) {
@@ -372,9 +364,11 @@ uint16_t Wiznet5500::sendFrame(const uint8_t* buf, uint16_t len) {
} else if (tmp & Sn_IR_TIMEOUT) {
setSn_IR(Sn_IR_TIMEOUT);
// There was a timeout
ethernet_arch_lwip_gpio_unmask();
return -1;
}
}
ethernet_arch_lwip_gpio_unmask();
return len;
}
+39 -2
View File
@@ -104,7 +104,7 @@ public:
protected:
static constexpr bool interruptIsPossible() {
return false;
return true;
}
/**
@@ -152,6 +152,7 @@ private:
SPIClass& _spi;
int8_t _cs;
int8_t _intr;
uint8_t _mac_address[6];
/**
@@ -319,7 +320,7 @@ private:
IR = 0x0015, ///< Interrupt Register (R/W)
_IMR_ = 0x0016, ///< Interrupt mask register (R/W)
SIR = 0x0017, ///< Socket Interrupt Register (R/W)
SIMR = 0x0018, ///< Socket Interrupt Mask Register (R/W)
_SIMR_ = 0x0018, ///< Socket Interrupt Mask Register (R/W)
_RTR_ = 0x0019, ///< Timeout register address (1 is 100us) (R/W)
_RCR_ = 0x001B, ///< Retry count register (R/W)
UIPR = 0x0028, ///< Unreachable IP register address in UDP mode (R)
@@ -520,6 +521,24 @@ private:
return wizchip_read(BlockSelectCReg, IR) & 0xF0;
}
/**
Set @ref SIR register
@param (uint8_t)ir Value to set @ref SIR register.
@sa getSIR()
*/
inline void setSIR(uint8_t ir) {
wizchip_write(BlockSelectCReg, SIR, ir);
}
/**
Get @ref SIR register
@return uint8_t. Value of @ref SIR register.
@sa setSIR()
*/
inline uint8_t getSIR() {
return wizchip_read(BlockSelectCReg, SIR);
}
/**
Set @ref _IMR_ register
@param (uint8_t)imr Value to set @ref _IMR_ register.
@@ -538,6 +557,24 @@ private:
return wizchip_read(BlockSelectCReg, _IMR_);
}
/**
Set @ref _SIMR_ register
@param (uint8_t)imr Value to set @ref _SIMR_ register.
@sa getIMR()
*/
inline void setSIMR(uint8_t imr) {
wizchip_write(BlockSelectCReg, _SIMR_, imr);
}
/**
Get @ref _SIMR_ register
@return uint8_t. Value of @ref _SIMR_ register.
@sa setSIMR()
*/
inline uint8_t getSIMR() {
return wizchip_read(BlockSelectCReg, _SIMR_);
}
/**
Set @ref PHYCFGR register
@param (uint8_t)phycfgr Value to set @ref PHYCFGR register.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.30700.0",
"version": "1.30702.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
+8 -8
View File
@@ -314,10 +314,10 @@
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/2.2.0/i686-w64-mingw32.picotool-f6fe6b7.240125.zip",
"archiveFileName": "i686-w64-mingw32.picotool-f6fe6b7.240125.zip",
"checksum": "SHA-256:f8a1ea6f0ea863b74a26b155fca780f24403f1069921e965f904ceac3d328dd5",
"size": "292401"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/2.2.0/i686-w64-mingw32.picotool-f6fe6b7.240125a.zip",
"archiveFileName": "i686-w64-mingw32.picotool-f6fe6b7.240125a.zip",
"checksum": "SHA-256:75a6672f56972bdc95cd6422a4709c372cd84e08ac07eefd8b1c2842b8617d99",
"size": "291095"
},
{
"host": "x86_64-apple-darwin",
@@ -335,10 +335,10 @@
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/2.2.0/x86_64-w64-mingw32.picotool-f6fe6b7.240125.zip",
"archiveFileName": "x86_64-w64-mingw32.picotool-f6fe6b7.240125.zip",
"checksum": "SHA-256:0e75f683223b5237051d1a1e47917f2b37b2b3a8ac11e516a0020dffbd49d3bd",
"size": "277241"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/2.2.0/x86_64-w64-mingw32.picotool-f6fe6b7.240125a.zip",
"archiveFileName": "x86_64-w64-mingw32.picotool-f6fe6b7.240125a.zip",
"checksum": "SHA-256:79a68e3d3d080cacfafc9c1546a3675ce5c7f858e6e85c690584251e63a2bee3",
"size": "276468"
}
]
},
+1 -1
View File
@@ -20,7 +20,7 @@
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=Raspberry Pi RP2040 Boards
version=3.7.0
version=3.7.2
# Required discoveries and monitors
# ---------------------------------
+1 -1
View File
@@ -14,7 +14,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleF
./libraries/MouseBT ./libraries/SerialBT ./libraries/HID_Bluetooth \
./libraries/JoystickBLE ./libraries/KeyboardBLE ./libraries/MouseBLE \
./libraries/lwIP_w5500 ./libraries/lwIP_w5100 ./libraries/lwIP_enc28j60 \
./libraries/SPISlave ; do
./libraries/SPISlave ./libraries/lwIP_ESPHost; do
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;
find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
done
+1 -1
View File
@@ -261,7 +261,7 @@ def get_drives():
print("Unable to build drive list");
sys.exit(1)
for line in to_str(r).split('\n'):
words = re.split('\s+', line)
words = re.split(r'\s+', line)
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
drives.append(words[0])
else: