Compare commits

...

14 Commits

Author SHA1 Message Date
franco 6369d9274a
Merge c759dd2eed into 28f4b951a7 2024-05-03 23:26:20 -03:00
supsm 28f4b951a7
Add extern "C" to isr_usbctrl in dev_lowlevel (#465)
add extern "C" to isr_usbctrl in dev_lowlevel
2024-05-02 17:38:02 +01:00
Gabriel Marcano 53556e5254
New example for ntp_client with LwIP Socket API (#434)
Implemented a new example derived from the existing ntp_client example,
but this time using the LwIP Socket API and FreeRTOS NO_SYS=0.
2024-05-02 17:31:21 +01:00
Trevor aef4834b49
Add the Pico W specific blink to the First Examples section (#493)
* Add the Pico W specific blink to the First Examples section

There is a prebuilt Pico W blink at https://datasheets.raspberrypi.com/soft/blink_picow.uf2 but I don't know if a rptl.io shortcut exists for it.

* Add rptl.io shortcut for picow_blink binary
2024-05-02 17:06:06 +01:00
Peter Harper 296b792d24
Remove duplicate FreeRTOSConfig.h files (#460)
Include FreeRTOSConfig_examples_common.h, similar to what we do for
lwipopts.h
2024-05-02 16:18:09 +01:00
Tauno Erik bf15aead5e
use LED_GPIO not 0 (#436) 2024-05-02 16:01:43 +01:00
Peter Harper 545185dcb2
Create a common mbedtls_config.h (#475) 2024-05-02 16:00:18 +01:00
Peter Harper cac44988b0
Compilation issues with latest version of Freertos (#429)
Fixes #428
2024-05-02 15:51:05 +01:00
pmarques-dev 7115bdd725
add high resolution quadrature encoder example (#405)
add high resolution quadrature encoder example

Author: Paulo Marques <Paulo.Marques@cambridge-machines.com>
2024-05-02 15:23:20 +01:00
Nathaniel J. McClatchey, PhD 51982de606
WS2812 example: Improve supported bandwidths (#486)
Adjusts constants to 3,3,4 to support higher bandwidths on any of WS2812, WS2812B, and SK6812 LEDs.
2024-05-02 13:04:08 +01:00
Peter Harper ebf796675e
Fix BT audio examples (#472)
When audio is initialised twice we get a error and make it more obvious
how to change the pins for audio hat hardware
2024-05-02 11:01:21 +01:00
FranCDoc c759dd2eed adding sleep to give time to connect to minicom 2024-04-14 02:10:28 -03:00
FranCDoc 3dba9a36b1 pico_enable_stdio_usb 2024-04-14 02:06:45 -03:00
FranCDoc 16b33ba21c added interrupt control for stable flash operations 2024-04-14 01:47:35 -03:00
31 changed files with 1615 additions and 359 deletions

View File

@ -5,13 +5,14 @@
See [Getting Started with the Raspberry Pi Pico](https://rptl.io/pico-get-started) and the README in the [pico-sdk](https://github.com/raspberrypi/pico-sdk) for information
on getting up and running.
### First Examples
### First Examples
App|Description | Link to prebuilt UF2
---|---|---
[hello_serial](hello_world/serial) | The obligatory Hello World program for Pico (Output over serial version) |
[hello_usb](hello_world/usb) | The obligatory Hello World program for Pico (Output over USB version) | https://rptl.io/pico-hello-usb
[blink](blink) | Blink an LED on and off. | https://rptl.io/pico-blink
[blink](blink) | Blink an LED on and off. Pico W should use [picow_blink](pico_w/wifi/blink). | https://rptl.io/pico-blink
[picow_blink](pico_w/wifi/blink) | Blinks the Pico W on-board LED (which is connected via the WiFi chip). | http://rptl.io/pico-w-blink
### ADC
@ -142,6 +143,7 @@ App|Description
[picow_freertos_iperf_server_sys](pico_w/wifi/freertos/iperf) | Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The LED is blinked in another task
[picow_freertos_ping_nosys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=1 mode.
[picow_freertos_ping_sys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The test app uses the lwIP _socket_ API in this case.
[picow_freertos_ntp_client_socket](pico_w/wifi/freertos/ntp_client_socket) | Connects to an NTP server using the LwIP Socket API with FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode.
### Pico W Bluetooth
@ -234,6 +236,7 @@ App|Description
[squarewave](pio/squarewave) | Drive a fast square wave onto a GPIO. This example accesses low-level PIO registers directly, instead of using the SDK functions.
[st7789_lcd](pio/st7789_lcd) | Set up PIO for 62.5 Mbps serial output, and use this to display a spinning image on a ST7789 serial LCD.
[quadrature_encoder](pio/quadrature_encoder) | A quadrature encoder using PIO to maintain counts independent of the CPU.
[quadrature_encoder_substep](pio/quadrature_encoder_substep) | High resolution speed measurement using a standard quadrature encoder
[uart_rx](pio/uart_rx) | Implement the receive component of a UART serial port. Attach it to the spare Arm UART to see it receive characters.
[uart_tx](pio/uart_tx) | Implement the transmit component of a UART serial port, and print hello world.
[ws2812](pio/ws2812) | Examples of driving WS2812 addressable RGB LEDs.

View File

@ -5,6 +5,7 @@ add_executable(flash_ssi_dma
target_link_libraries(flash_ssi_dma
pico_stdlib
hardware_dma
hardware_sync
)
# create map/bin/hex file etc.
@ -12,3 +13,6 @@ pico_add_extra_outputs(flash_ssi_dma)
# add url via pico_set_program_url
example_auto_set_url(flash_ssi_dma)
pico_enable_stdio_usb(flash_ssi_dma 1)
pico_enable_stdio_uart(flash_ssi_dma 0)

View File

@ -11,6 +11,7 @@
#include "pico/time.h"
#include "hardware/dma.h"
#include "hardware/structs/ssi.h"
#include "hardware/sync.h"
// This example DMAs 16kB of data from the start of flash to SRAM, and
// measures the transfer speed.
@ -66,11 +67,17 @@ uint32_t *expect = (uint32_t *) XIP_NOCACHE_NOALLOC_BASE;
int main() {
stdio_init_all();
sleep_ms(2500);
memset(rxdata, 0, DATA_SIZE_WORDS * sizeof(uint32_t));
printf("Starting DMA\n");
uint32_t start_time = time_us_32();
uint32_t ints = save_and_disable_interrupts();
flash_bulk_read(rxdata, 0, DATA_SIZE_WORDS, 0);
restore_interrupts(ints);
uint32_t finish_time = time_us_32();
printf("DMA finished\n");

View File

@ -153,8 +153,9 @@ static int btstack_audio_pico_sink_init(
playback_callback = playback;
btstack_audio_pico_audio_buffer_pool = init_audio(samplerate, channels);
if (!btstack_audio_pico_audio_buffer_pool) {
btstack_audio_pico_audio_buffer_pool = init_audio(samplerate, channels);
}
return 0;
}

View File

@ -105,9 +105,11 @@
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 2
#define configNUMBER_OF_CORES configNUM_CORES
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 1
#define configUSE_PASSIVE_IDLE_HOOK 0
#endif
/* RP2040 specific */

View File

@ -1 +1,6 @@
picow_bt_example(hfp_hf_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder)
add_library(hfp_hf_demo_pins INTERFACE)
target_compile_definitions(hfp_hf_demo_pins INTERFACE
PICO_AUDIO_I2S_DATA_PIN=9
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
)
picow_bt_example(hfp_hf_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder hfp_hf_demo_pins)

View File

@ -1 +1,6 @@
picow_bt_example(mod_player pico_btstack_hxcmod_player)
add_library(mod_player_pins INTERFACE)
target_compile_definitions(mod_player_pins INTERFACE
PICO_AUDIO_I2S_DATA_PIN=9
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
)
picow_bt_example(mod_player pico_btstack_hxcmod_player mod_player_pins)

View File

@ -1 +1,6 @@
picow_bt_example(sine_player)
add_library(sine_player_pins INTERFACE)
target_compile_definitions(sine_player_pins INTERFACE
PICO_AUDIO_I2S_DATA_PIN=9
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
)
picow_bt_example(sine_player sine_player_pins)

View File

@ -97,10 +97,10 @@ static int test_server_content(const char *request, const char *params, char *re
if (led_param == 1) {
if (led_state) {
// Turn led on
cyw43_gpio_set(&cyw43_state, 0, true);
cyw43_gpio_set(&cyw43_state, LED_GPIO, true);
} else {
// Turn led off
cyw43_gpio_set(&cyw43_state, 0, false);
cyw43_gpio_set(&cyw43_state, LED_GPIO, false);
}
}
}

View File

@ -5,4 +5,5 @@ else()
add_subdirectory(iperf)
add_subdirectory(ping)
endif()
add_subdirectory(ntp_client_socket)
endif()

View File

@ -0,0 +1,145 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_EXAMPLES_COMMON_H
#define FREERTOS_CONFIG_EXAMPLES_COMMON_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 2
#define configNUMBER_OF_CORES configNUM_CORES
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 1
#define configUSE_PASSIVE_IDLE_HOOK 0
#endif
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

View File

@ -7,6 +7,7 @@ target_compile_definitions(picow_freertos_iperf_server_nosys PRIVATE
)
target_include_directories(picow_freertos_iperf_server_nosys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
)
target_link_libraries(picow_freertos_iperf_server_nosys
@ -27,6 +28,7 @@ target_compile_definitions(picow_freertos_iperf_server_sys PRIVATE
)
target_include_directories(picow_freertos_iperf_server_sys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
)
target_link_libraries(picow_freertos_iperf_server_sys

View File

@ -1,143 +1,7 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
// This example uses a common include to avoid repetition
#include "FreeRTOSConfig_examples_common.h"
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 2
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 1
#endif
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

View File

@ -0,0 +1,20 @@
add_executable(picow_freertos_ntp_client_socket
picow_freertos_ntp_client_socket.c
)
target_compile_definitions(picow_freertos_ntp_client_socket PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h)
LWIP_SOCKET=1 # we need the socket API (generally this would be in your lwipopts.h)
)
target_include_directories(picow_freertos_ntp_client_socket PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
)
target_link_libraries(picow_freertos_ntp_client_socket
pico_cyw43_arch_lwip_sys_freertos
pico_stdlib
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
)
pico_add_extra_outputs(picow_freertos_ntp_client_socket)

View File

@ -0,0 +1,35 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
// This example uses a common include to avoid repetition
#include "FreeRTOSConfig_examples_common.h"
#endif /* FREERTOS_CONFIG_H */

View File

@ -0,0 +1,25 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// Generally you would define your own explicit list of lwIP options
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
//
// This example uses a common include to avoid repetition
#include "lwipopts_examples_common.h"
#if !NO_SYS
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 1024
#define DEFAULT_RAW_RECVMBOX_SIZE 8
#define DEFAULT_UDP_RECVMBOX_SIZE 8
#define DEFAULT_TCP_RECVMBOX_SIZE 8
#define TCPIP_MBOX_SIZE 8
#define LWIP_TIMEVAL_PRIVATE 0
// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#define LWIP_SO_RCVTIMEO 1
#endif
#endif

View File

@ -0,0 +1,189 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#include "lwip/ip4_addr.h"
#include "lwip/dns.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "FreeRTOS.h"
#include "task.h"
#ifndef RUN_FREERTOS_ON_CORE
#define RUN_FREERTOS_ON_CORE 0
#endif
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )
#define NTP_SERVER ("pool.ntp.org")
#define NTP_MSG_LEN (48)
#define NTP_PORT (123)
// seconds between 1 Jan 1900 and 1 Jan 1970
#define NTP_DELTA (2208988800)
#define ntpEST_TIME (30 * 1000)
#define NTP_FAIL_TIME (10)
void main_task(__unused void *params) {
if (cyw43_arch_init()) {
printf("failed to initialise\n");
vTaskDelete(NULL);
}
cyw43_arch_enable_sta_mode();
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
vTaskDelete(NULL);
} else {
printf("Connected.\n");
}
while(true) {
const struct addrinfo ntp_info = {
.ai_flags = 0,
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = 0,
};
struct addrinfo *dns_result = NULL;
printf("Trying DNS...\n");
int err = getaddrinfo(NTP_SERVER, "123", &ntp_info, &dns_result);
if (err != 0)
{
printf("DNS lookup failed with error: %d\n", err);
continue;
}
#ifndef INET6_ADDRSTRLEN
char address[INET_ADDRSTRLEN] = {0};
#else
char address[INET6_ADDRSTRLEN] = {0};
#endif
ip_addr_t ip_addr;
#if LWIP_IPV4
if (dns_result->ai_addr->sa_family == AF_INET) {
const struct sockaddr_in *sock_addr = (struct sockaddr_in*)dns_result->ai_addr;
inet_addr_to_ip4addr(ip_2_ip4(&ip_addr), &sock_addr->sin_addr);
IP_SET_TYPE(&ip_addr, IPADDR_TYPE_V4);
}
#endif
#if LWIP_IPV6
if (dns_result->ai_addr->sa_family == AF_INET6) {
const struct sockaddr_in6 *sock_addr = (struct sockaddr_in6*)dns_result->ai_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&ip_addr), &sock_addr->sin6_addr);
IP_SET_TYPE(&ip_addr, IPADDR_TYPE_V6);
}
#endif
inet_ntop(dns_result->ai_family, &ip_addr, address, sizeof(address));
printf("Got DNS response: %s\n", address);
int sock = socket(dns_result->ai_family, dns_result->ai_socktype, dns_result->ai_protocol);
if (sock == -1)
{
printf("Failed to allocate socket");
freeaddrinfo(dns_result);
continue;
}
struct timeval timeout = {
.tv_sec = NTP_FAIL_TIME,
};
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
err = connect(sock, dns_result->ai_addr, dns_result->ai_addrlen);
freeaddrinfo(dns_result);
if (err == -1)
{
printf("Failed to connect to NTP server");
close(sock);
continue;
}
unsigned char request[NTP_MSG_LEN] = {0x1b, 0};
int amount = send(sock, request, NTP_MSG_LEN, 0);
if (amount != NTP_MSG_LEN)
{
printf("We were unable to send the complete NTP request");
close(sock);
continue;
}
amount = recv(sock, request, NTP_MSG_LEN, 0);
close(sock);
if (amount != NTP_MSG_LEN)
{
printf("We did not receive a complete NTP response");
continue;
}
uint8_t mode = request[0] & 0x7;
uint8_t stratum = request[1];
// Check the result
if (amount == NTP_MSG_LEN &&
mode == 0x4 &&
stratum != 0)
{
uint8_t seconds_buf[4] = {};
memcpy(seconds_buf, request + 40, 4);
uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
uint32_t seconds_since_1970 = seconds_since_1900 - NTP_DELTA;
time_t epoch = seconds_since_1970;
struct tm *utc = gmtime(&epoch);
printf("got ntp response: %02d/%02d/%04d %02d:%02d:%02d\n", utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
utc->tm_hour, utc->tm_min, utc->tm_sec);
}
// This assumes one tick is one ms, which is true for the default configuration
vTaskDelay(ntpEST_TIME);
}
cyw43_arch_deinit();
}
void vLaunch( void) {
TaskHandle_t task;
xTaskCreate(main_task, "TestMainThread", 4096, NULL, TEST_TASK_PRIORITY, &task);
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
// we must bind the main task to one core (well at least while the init is called)
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
// takes care of it otherwise)
vTaskCoreAffinitySet(task, 1);
#endif
/* Start the tasks and timer running. */
vTaskStartScheduler();
}
int main( void )
{
stdio_init_all();
/* Configure the hardware ready to run the demo. */
const char *rtos_name;
#if ( portSUPPORT_SMP == 1 )
rtos_name = "FreeRTOS SMP";
#else
rtos_name = "FreeRTOS";
#endif
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
printf("Starting %s on both cores:\n", rtos_name);
vLaunch();
#elif ( RUN_FREERTOS_ON_CORE == 1 )
printf("Starting %s on core 1:\n", rtos_name);
multicore_launch_core1(vLaunch);
while (true);
#else
printf("Starting %s on core 0:\n", rtos_name);
vLaunch();
#endif
return 0;
}

View File

@ -9,6 +9,7 @@ if (EXISTS ${PICO_LWIP_CONTRIB_PATH}/apps/ping/ping.c)
)
target_include_directories(picow_freertos_ping_nosys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
${PICO_LWIP_CONTRIB_PATH}/apps/ping
)
@ -33,6 +34,7 @@ if (EXISTS ${PICO_LWIP_CONTRIB_PATH}/apps/ping/ping.c)
)
target_include_directories(picow_freertos_ping_sys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
${PICO_LWIP_CONTRIB_PATH}/apps/ping
)

View File

@ -1,143 +1,7 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
// This example uses a common include to avoid repetition
#include "FreeRTOSConfig_examples_common.h"
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 2
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 1
#endif
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

View File

@ -0,0 +1,71 @@
#ifndef MBEDTLS_CONFIG_EXAMPLES_COMMON_H
#define MBEDTLS_CONFIG_EXAMPLES_COMMON_H
/* Workaround for some mbedtls source files using INT_MAX without including limits.h */
#include <limits.h>
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_SERVER_NAME_INDICATION
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_AES_FEWER_TABLES
/* TLS 1.2 */
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_GCM_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ASN1_WRITE_C
// The following is needed to parse a certificate
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_BASE64_C
#endif

View File

@ -8,7 +8,7 @@ target_compile_definitions(picow_tls_client_background PRIVATE
)
target_include_directories(picow_tls_client_background PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts and mbedtls_config.h
)
target_link_libraries(picow_tls_client_background
pico_cyw43_arch_lwip_threadsafe_background
@ -28,7 +28,7 @@ target_compile_definitions(picow_tls_client_poll PRIVATE
)
target_include_directories(picow_tls_client_poll PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts and mbedtls_config.h
)
target_link_libraries(picow_tls_client_poll
pico_cyw43_arch_lwip_poll
@ -52,7 +52,7 @@ target_compile_definitions(picow_tls_verify_background PRIVATE
)
target_include_directories(picow_tls_verify_background PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts and mbedtls_config.h
)
target_link_libraries(picow_tls_verify_background
pico_cyw43_arch_lwip_threadsafe_background

View File

@ -1,66 +1,6 @@
/* Workaround for some mbedtls source files using INT_MAX without including limits.h */
#include <limits.h>
#ifndef MBEDTLS_CONFIG_TLS_CLIENT_H
#define MBEDTLS_CONFIG_TLS_CLIENT_H
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
#include "mbedtls_config_examples_common.h"
#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_SERVER_NAME_INDICATION
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_AES_FEWER_TABLES
/* TLS 1.2 */
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_GCM_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ASN1_WRITE_C
// The following is needed to parse a certificate
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_BASE64_C
#endif

View File

@ -13,6 +13,7 @@ if (NOT PICO_NO_HARDWARE)
add_subdirectory(pio_blink)
add_subdirectory(pwm)
add_subdirectory(quadrature_encoder)
add_subdirectory(quadrature_encoder_substep)
add_subdirectory(spi)
add_subdirectory(squarewave)
add_subdirectory(st7789_lcd)

View File

@ -0,0 +1,20 @@
add_executable(pio_quadrature_encoder_substep)
pico_generate_pio_header(pio_quadrature_encoder_substep ${CMAKE_CURRENT_LIST_DIR}/quadrature_encoder_substep.pio)
target_sources(pio_quadrature_encoder_substep PRIVATE quadrature_encoder_substep.c)
target_link_libraries(pio_quadrature_encoder_substep PRIVATE
pico_stdlib
pico_multicore
hardware_pio
hardware_pwm
hardware_watchdog
)
pico_enable_stdio_usb(pio_quadrature_encoder_substep 1)
pico_add_extra_outputs(pio_quadrature_encoder_substep)
# add url via pico_set_program_url
example_auto_set_url(pio_quadrature_encoder_substep)

View File

@ -0,0 +1,86 @@
# Sub-Step Quadrature Encoder
## The problem
Hardware peripherals to read quadrature encoders (and the quadrature encoder example) count steps by looking at the sequence of phase states read from a quadrature encoder.
To estimate the encoder speed, the user can check how many steps were counted over a period of time. For instance, if the count was 120 at the beginning and was 134 10ms later, we can estimate that the speed is 14 steps in 10ms or 1400 steps per second.
This works relatively well for high counts, but at low speeds (or high sample rates), the quantization effect of looking at integer counts can introduce a high level of quantization noise in the speed measurement.
A different approach that would work better at low speeds, would be to measure the time it takes to advance one step and use its inverse to compute the speed. For instance, if one step takes 540us, then the speed is 1/0.000540 = ~1852 steps per second.
Unfortunately, as speed increases the resolution of this method decreases rapidly. At 100.000 steps per second, a step takes 10us. Measuring 9, 10 or 11 us per step will give speeds of 111k, 100k or 90k steps per second, respectively.
Moreover, especially in low cost encoders, the phases are not all the same size which introduces another source of measurement noise if not compensated properly.
## The Solution
The "sub-step" quadrature encoder code solves this problem by using an hybrid approach: the PIO code keeps track of the integer step count, but also how long ago was the last transition and the direction of that transition. The high level code can then use that information to compute a speed estimate that doesn't suffer from the integer quantization problem of just counting steps and can support high step rates as well.
The high level code also takes into account and compensates the phase size differences of the encoder.
The chart below shows the speed estimate using just integer step counts in red and the sub-step speed estimate in blue for an encoder connected to a DC motor doing some voltage step changes.
![](images/chart.svg)
Note that unlike what we would get by doing a low-pass filter on the integer count signal, the sub-step version has no delay and does not limit the frequency response of the encoder.
## Usage
Because we need to keep some state information to compute a speed estimate from the previous transitions, the code requires a `substep_state_t` structure per encoder.
There are only 2 functions the user code needs to use:
- `substep_init_state`: initialize the PIO code and state structure
- `substep_update`: read the PIO and update the `speed` and `position` fields of the `substep_state_t` structure. The position is given in sub-steps and the speed is given in sub-steps per second
Note that since the PIO code uses 32 instructions and must be loaded at offset 0, the PIO used by this code can not be used for other purposes but can handle up to 4 encoders (one per state machine).
## Phase calibration
To increase the precision of the speed estimate, the user can run a calibration function to measure the relative sizes of the phases of the encoder. The sub-step code will then use this information to compensate the phase size differences while computing speed estimates. This is not strictly necessary, but if not done, the code will assume equal size phases, which will introduce noise, especially at low speeds.
Note that for an encoder to have perfectly balanced 90 degree phases, each individual phase would require a perfect 50% duty cycle and the phases would need to be exactly 90 degrees apart. That is rarely the case in low cost encoders.
To calibrate phase sizes (optional, but highly recommended), there are two more functions:
- `substep_set_calibration_data`: set the relative phase positions. This function should always be called at program start, after calling `substep_init_state`
- `substep_calibrate_phases`: this function should be used offline, on a test program, to get the phase sizes of an encoder. After getting the sizes, these can be passed as constants to `substep_set_calibration_data` without having to run this function again. To measure the phase sizes, make the encoder rotate forward (increasing step order) and call this function to measure the relative sizes of the encoder phases. It outputs the parameters that should be passed to `substep_set_calibration_data` to compensate for phase sizes. Ideally, the encoder should be rotating at a constant speed of around 2.000 steps per second, but any value from 200 sps to 20.000 sps without any abrupt changes in speed, should work as well
If you are curious about how unbalanced your encoder is, the calibration code for a perfect encoder should output `substep_set_calibration_data(&state, 64, 128, 192);`, i.e., each phase should be exactly 64 sub-steps in size
## Sub-step vs simple quadrature encoder code
Compared with the simple step counting version, this version has the advantage that it uses the information from the transition times to extract a much better speed and position estimate.
The disadvantages are a larger PIO program (32 instead of 24 instructions) and a bit more CPU time used when computing the speed estimate (just once per sample).
Like the simple version, it doesn't use CPU time while counting steps and it's only the update function that uses CPU time. Note that this function is called at the control frequency of your system, say 100Hz, and so the CPU time used is independent of the step rate of the encoder. To use as little CPU as possible, this function only uses integer arithmetic.
Note: the `substep_state_t` structure has a `raw_step` field that contains the same step count that would have been returned by the simple quadrature encoder code. This can be useful if, for instance, we have a project with a couple of DC motors with encoders (that would benefit from using the sub-step version), but also a rotary encoder for the user interface (for which we only need integer steps).
## Implementation details
The chart below illustrates how the sub-step works. The horizontal scale is time in micro-seconds, the vertical step is in sub-steps. 4 hardware steps (one cycle) are always 256 sub-steps. To simplify, lets assume the phases are balanced and each step takes exactly 64 sub-steps.
![](images/steps.svg)
The red line is the upper bound of the encoder position, whereas the blue line is the lower bound. The yellow line is the speed estimate.
At the start, the encoder is stopped at hardware step 3, so the sub-step estimate is between 192 and 256.
At 30ms, we read the data from the PIO and there was a transition at ~21ms and the current integer step is 4. At the time of the transition the lower and upper bounds for the position touch, because we know exactly where the encoder is in that instant.
At this point we don't know much about the speed. The sub-step position of the encoder could have been close to 256 (close to the upper bound) and it could still be there now (close to the lower bound).
At 40ms, we read the PIO again. The encoder as made another step so we know the sub-step position is between 320 and 384. We also know there was a transition at ~34ms, so we can compute a speed estimate as the encoder did 64 sub-steps in 34 - 21 = 13ms (note: the actual code uses micro-seconds).
At 50ms, the encoder actually did 2 steps, the sub-step position is now between 448 and 512 and the last transition was at ~49ms. Note that there were two transitions in this period, but we only get the latest transition from the PIO code. This still allows us to compute a new speed estimate, as we made 128 sub-steps in 49 - 34 = 15 ms.
On top of using actual transitions to compute the speed, the current step position is also used to give a upper and lower bound on the speed so that the code can react faster to large variations in speed.
To compensate for unbalanced phase sizes, the sub-step position assigned to each hardware step transition is not a multiple of 64 but instead depends on the phase size calibration. The lower bound of phase 0 is always a multiple of 256, though.

View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="395.11mm" height="245.53mm" baseProfile="tiny" version="1.2" viewBox="0 0 1120 696" xmlns="http://www.w3.org/2000/svg">
<title>Qt SVG Document</title>
<desc>Generated with Qt</desc>
<g fill="none" fill-rule="evenodd" font-family="Sans" font-weight="400">
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 606.5 102.5 606.5"/>
<polyline points="1087.5 606.5 1080.5 606.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 29.052 613.6)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">-80000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 542.5 102.5 542.5"/>
<polyline points="1087.5 542.5 1080.5 542.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 29.052 549.48)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">-60000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 478.5 102.5 478.5"/>
<polyline points="1087.5 478.5 1080.5 478.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 29.052 485.37)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">-40000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 414.5 102.5 414.5"/>
<polyline points="1087.5 414.5 1080.5 414.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 29.052 421.25)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">-20000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 351.5 102.5 351.5"/>
<polyline points="1087.5 351.5 1080.5 351.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 70.125 357.14)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 0</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 287.5 102.5 287.5"/>
<polyline points="1087.5 287.5 1080.5 287.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 30.054 293.02)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 20000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 223.5 102.5 223.5"/>
<polyline points="1087.5 223.5 1080.5 223.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 30.054 228.91)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 40000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 159.5 102.5 159.5"/>
<polyline points="1087.5 159.5 1080.5 159.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 30.054 164.79)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 60000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 95.5 102.5 95.5"/>
<polyline points="1087.5 95.5 1080.5 95.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 30.054 101.68)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 80000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 31.5 102.5 31.5"/>
<polyline points="1087.5 31.5 1080.5 31.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 20.036 37.567)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 100000</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="139.5 655.5 139.5 648.5"/>
<polyline points="139.5 19.5 139.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 117.71 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2500</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="258.5 655.5 258.5 648.5"/>
<polyline points="258.5 19.5 258.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 235.92 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2550</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="376.5 655.5 376.5 648.5"/>
<polyline points="376.5 19.5 376.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 355.13 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2600</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="495.5 655.5 495.5 648.5"/>
<polyline points="495.5 19.5 495.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 473.34 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2650</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="614.5 655.5 614.5 648.5"/>
<polyline points="614.5 19.5 614.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 592.56 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2700</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="732.5 655.5 732.5 648.5"/>
<polyline points="732.5 19.5 732.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 711.77 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2750</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="851.5 655.5 851.5 648.5"/>
<polyline points="851.5 19.5 851.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 829.98 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2800</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="969.5 655.5 969.5 648.5"/>
<polyline points="969.5 19.5 969.5 26.5"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 949.2 681.72)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve"> 2850</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 19.5 95.5 655.5 1087.5 655.5 1087.5 19.5 95.5 19.5" fill="none"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 954.7 41.574)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">integer</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#ff6060" stroke-linecap="round" stroke-linejoin="round">
<path d="m1020.5 36.5h47" fill-rule="evenodd"/>
<polyline points="95 351 96.9 351 99.3 351 101.7 351 104.1 351 106.4 351 108.8 351 111.2 351 113.5 351 115.9 351 118.3 351 120.7 351 123 351 125.4 351 127.8 351 130.1 351 132.5 371.4 134.9 432.8 137.3 453.2 139.6 473.7 142 494.1 144.4 494.1 146.7 514.5 149.1 514.5 151.5 514.5 153.9 535 156.2 514.5 158.6 535 161 535 163.4 535 165.7 535 168.1 535 170.5 535 172.8 535 175.2 535 177.6 535 180 535 182.3 555.4 184.7 535 187.1 535 189.4 535 191.8 535 194.2 555.4 196.6 535 198.9 535 201.3 555.4 203.7 535 206 535 208.4 555.4 210.8 535 213.2 535 215.5 555.4 217.9 535 220.3 555.4 222.7 535 225 555.4 227.4 535 229.8 535 232.1 555.4 234.5 535 236.9 555.4 239.3 535 241.6 555.4 244 535 246.4 555.4 248.7 535 251.1 555.4 253.5 535 255.9 555.4 258.2 535 260.6 555.4 263 535 265.3 555.4 267.7 535 270.1 555.4 272.5 555.4 274.8 535 277.2 535 279.6 555.4 282 555.4 284.3 555.4 286.7 575.9 289.1 575.9 291.4 596.3 293.8 616.8 296.2 596.3 298.6 616.8 300.9 616.8 303.3 596.3 305.7 616.8 308 616.8 310.4 616.8 312.8 596.3 315.2 616.8 317.5 616.8 319.9 616.8 322.3 616.8 324.6 616.8 327 616.8 329.4 616.8 331.8 616.8 334.1 616.8 336.5 616.8 338.9 596.3 341.3 637.2 343.6 596.3 346 637.2 348.4 596.3 350.7 616.8 353.1 616.8 355.5 616.8 357.9 616.8 360.2 616.8 362.6 616.8 365 616.8 367.3 616.8 369.7 616.8 372.1 616.8 374.5 616.8 376.8 616.8 379.2 616.8 381.6 616.8 383.9 616.8 386.3 616.8 388.7 637.2 391.1 616.8 393.4 616.8 395.8 616.8 398.2 616.8 400.6 616.8 402.9 616.8 405.3 616.8 407.7 616.8 410 637.2 412.4 616.8 414.8 616.8 417.2 616.8 419.5 616.8 421.9 616.8 424.3 616.8 426.6 637.2 429 616.8 431.4 616.8 433.8 616.8 436.1 596.3 438.5 555.4 440.9 514.5 443.2 494.1 445.6 494.1 448 473.7 450.4 453.2 452.7 473.7 455.1 453.2 457.5 453.2 459.9 473.7 462.2 453.2 464.6 453.2 467 453.2 469.3 453.2 471.7 453.2 474.1 453.2 476.5 453.2 478.8 453.2 481.2 453.2 483.6 453.2 485.9 453.2 488.3 453.2 490.7 453.2 493.1 453.2 495.4 453.2 497.8 453.2 500.2 453.2 502.5 453.2 504.9 473.7 507.3 453.2 509.7 453.2 512 453.2 514.4 453.2 516.8 453.2 519.2 453.2 521.5 453.2 523.9 453.2 526.3 473.7 528.6 453.2 531 453.2 533.4 453.2 535.8 453.2 538.1 453.2 540.5 453.2 542.9 473.7 545.2 453.2 547.6 453.2 550 453.2 552.4 453.2 554.7 453.2 557.1 453.2 559.5 473.7 561.8 453.2 564.2 453.2 566.6 453.2 569 453.2 571.3 473.7 573.7 453.2 576.1 453.2 578.5 473.7 580.8 453.2 583.2 453.2 585.6 453.2 587.9 494.1 590.3 514.5 592.7 555.4 595.1 575.9 597.4 596.3 599.8 596.3 602.2 596.3 604.5 616.8 606.9 596.3 609.3 616.8 611.7 596.3 614 616.8 616.4 596.3 618.8 616.8 621.1 616.8 623.5 616.8 625.9 596.3 628.3 616.8 630.6 616.8 633 616.8 635.4 596.3 637.8 616.8 640.1 616.8 642.5 596.3 644.9 616.8 647.2 616.8 649.6 616.8 652 616.8 654.4 596.3 656.7 616.8 659.1 616.8 661.5 596.3 663.8 616.8 666.2 616.8 668.6 616.8 671 616.8 673.3 596.3 675.7 616.8 678.1 616.8 680.4 616.8 682.8 616.8 685.2 616.8 687.6 616.8 689.9 596.3 692.3 616.8 694.7 616.8 697.1 616.8 699.4 616.8 701.8 616.8 704.2 616.8 706.5 596.3 708.9 616.8 711.3 616.8 713.7 616.8 716 616.8 718.4 616.8 720.8 616.8 723.1 596.3 725.5 637.2 727.9 596.3 730.3 616.8 732.6 616.8 735 616.8 737.4 616.8 739.7 596.3 742.1 535 744.5 535 746.9 473.7 749.2 494.1 751.6 473.7 754 453.2 756.4 473.7 758.7 453.2 761.1 453.2 763.5 453.2 765.8 453.2 768.2 473.7 770.6 453.2 773 453.2 775.3 453.2 777.7 453.2 780.1 453.2 782.4 453.2 784.8 453.2 787.2 453.2 789.6 453.2 791.9 453.2 794.3 453.2 796.7 453.2 799 453.2 801.4 453.2 803.8 453.2 806.2 453.2 808.5 453.2 810.9 453.2 813.3 473.7 815.7 453.2 818 453.2 820.4 453.2 822.8 453.2 825.1 453.2 827.5 453.2 829.9 453.2 832.3 453.2 834.6 473.7 837 432.8 839.4 473.7 841.7 453.2 844.1 453.2 846.5 453.2 848.9 453.2 851.2 453.2 853.6 453.2 856 473.7 858.3 453.2 860.7 453.2 863.1 453.2 865.5 453.2 867.8 453.2 870.2 453.2 872.6 473.7 875 453.2 877.3 453.2 879.7 453.2 882.1 453.2 884.4 473.7 886.8 453.2 889.2 453.2 891.6 371.4 893.9 269.2 896.3 248.8 898.7 187.4 901 167 903.4 167 905.8 146.6 908.2 146.6 910.5 126.1 912.9 126.1 915.3 126.1 917.6 126.1 920 105.7 922.4 126.1 924.8 105.7 927.1 126.1 929.5 105.7 931.9 105.7 934.3 126.1 936.6 105.7 939 105.7 941.4 105.7 943.7 126.1 946.1 105.7 948.5 105.7 950.9 105.7 953.2 105.7 955.6 105.7 958 105.7 960.3 105.7 962.7 105.7 965.1 105.7 967.5 85.2 969.8 105.7 972.2 105.7 974.6 105.7 976.9 85.2 979.3 105.7 981.7 105.7 984.1 85.2 986.4 105.7 988.8 85.2 991.2 105.7 993.6 85.2 995.9 105.7 998.3 85.2 1000.7 105.7 1003 85.2 1005.4 85.2 1007.8 105.7 1010.2 85.2 1012.5 85.2 1014.9 85.2 1017.3 85.2 1019.6 105.7 1022 85.2 1024.4 85.2 1026.8 85.2 1029.1 85.2 1031.5 85.2 1033.9 85.2 1036.2 85.2 1038.6 85.2 1041 85.2 1043.4 167 1045.7 289.7 1048.1 371.4 1050.5 351 1052.9 371.4 1055.2 351 1057.6 351 1060 351 1062.3 351 1064.7 351 1067.1 351 1069.5 351 1071.8 351 1074.2 351 1076.6 351 1078.9 351 1081.3 351 1083.7 351 1086.1 351 1086.1 351 1087.9 351" fill="none"/>
</g>
<g transform="matrix(1.0018 0 0 1.0018 949.7 60.608)" font-size="9" stroke="#000" stroke-linecap="square" stroke-linejoin="bevel">
<text fill="#000000" font-family="Sans" font-size="9" font-weight="400" stroke="none" xml:space="preserve">substep</text>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#00f" stroke-linecap="round" stroke-linejoin="round">
<path d="m1020.5 55.5h47" fill-rule="evenodd"/>
<polyline points="95 351 96.9 351 99.3 351 101.7 351 104.1 351 106.4 351 108.8 351 111.2 351 113.5 351 115.9 351 118.3 351 120.7 351 123 351 125.4 351 127.8 351 130.1 351 132.5 351 134.9 411.5 137.3 452.3 139.6 473.6 142 488.8 144.4 499.8 146.7 508.2 149.1 515.5 151.5 519.9 153.9 523.4 156.2 525.1 158.6 526.9 161 529.7 163.4 530.3 165.7 532.8 168.1 532.3 170.5 533.6 172.8 533.7 175.2 535.4 177.6 534.6 180 535.8 182.3 536.3 184.7 535.9 187.1 537.3 189.4 537.1 191.8 537.6 194.2 537.7 196.6 537.9 198.9 539.6 201.3 538.4 203.7 539.2 206 540.7 208.4 540.4 210.8 540.3 213.2 540.7 215.5 540.7 217.9 540.8 220.3 541.2 222.7 541.8 225 542.1 227.4 541.6 229.8 542.7 232.1 542.4 234.5 541.9 236.9 541.5 239.3 543.5 241.6 543.2 244 542.8 246.4 543 248.7 542.8 251.1 542.7 253.5 542.1 255.9 543.3 258.2 543 260.6 542.8 263 542.6 265.3 542.7 267.7 543.4 270.1 543.8 272.5 543.5 274.8 543.3 277.2 544.7 279.6 543 282 544.3 284.3 555.1 286.7 572.9 289.1 585.9 291.4 593.9 293.8 599.9 296.2 604 298.6 606.2 300.9 606.2 303.3 607.5 305.7 609.5 308 608.7 310.4 608.4 312.8 609.2 315.2 610 317.5 610.8 319.9 609.7 322.3 612.2 324.6 611.4 327 613 329.4 612.4 331.8 612.9 334.1 611.6 336.5 613.3 338.9 612.6 341.3 612 343.6 613 346 614.1 348.4 613.1 350.7 612.1 353.1 613.8 355.5 612.3 357.9 612.9 360.2 611.3 362.6 612.4 365 612.1 367.3 614.2 369.7 613.1 372.1 612.8 374.5 613.5 376.8 614.6 379.2 613.3 381.6 616 383.9 614.9 386.3 616.4 388.7 616.5 391.1 615.6 393.4 616.8 395.8 615.7 398.2 615.2 400.6 616.2 402.9 616.5 405.3 614.5 407.7 616.4 410 615.4 412.4 614.8 414.8 615.8 417.2 615.4 419.5 617.4 421.9 616.9 424.3 616.8 426.6 618.2 429 616.6 431.4 618.5 433.8 617.1 436.1 594.6 438.5 550.2 440.9 520.4 443.2 498.1 445.6 482.7 448 471.7 450.4 465.6 452.7 461.3 455.1 458.4 457.5 456.3 459.9 454.6 462.2 453.2 464.6 454 467 452.9 469.3 452.7 471.7 453 474.1 452.6 476.5 451.7 478.8 453.8 481.2 452.3 483.6 452.7 485.9 452 488.3 453.3 490.7 452.3 493.1 453.7 495.4 452.8 497.8 453 500.2 453.6 502.5 453.5 504.9 453.2 507.3 452.8 509.7 454.5 512 453.9 514.4 453.9 516.8 454.3 519.2 454 521.5 453.2 523.9 455.7 526.3 454.2 528.6 454.5 531 454.6 533.4 455.3 535.8 454.9 538.1 453.9 540.5 456.3 542.9 454.8 545.2 455.1 547.6 455.1 550 455.7 552.4 455.8 554.7 454.7 557.1 457.2 559.5 455.5 561.8 456 564.2 455.9 566.6 456.3 569 456.2 571.3 456.4 573.7 455.8 576.1 457.2 578.5 456.6 580.8 456 583.2 456.8 585.6 456.3 587.9 480.2 590.3 523.4 592.7 551.3 595.1 570.4 597.4 583.7 599.8 592.1 602.2 597.9 604.5 602 606.9 603.8 609.3 605.1 611.7 606.2 614 606.9 616.4 607 618.8 606.4 621.1 607.8 623.5 607 625.9 607.3 628.3 607.3 630.6 608.3 633 608.7 635.4 607.9 637.8 607 640.1 609.1 642.5 608.7 644.9 608.3 647.2 609.2 649.6 608.3 652 608.5 654.4 608.3 656.7 607.9 659.1 609.7 661.5 608.8 663.8 608.9 666.2 608.6 668.6 609.6 671 610.1 673.3 609.8 675.7 608.9 678.1 610.9 680.4 609.6 682.8 610.5 685.2 609.6 687.6 610.5 689.9 610.5 692.3 610 694.7 611.9 697.1 610.8 699.4 610.9 701.8 611.7 704.2 611.7 706.5 611.4 708.9 610.2 711.3 611.8 713.7 610.1 716 611.1 718.4 610.5 720.8 611.4 723.1 611.3 725.5 612.4 727.9 611.9 730.3 612.2 732.6 612 735 612.7 737.4 612.8 739.7 588.8 742.1 545.9 744.5 515 746.9 495 749.2 479.7 751.6 470.6 754 465.5 756.4 460.7 758.7 457.2 761.1 456 763.5 454.3 765.8 454.7 768.2 453.5 770.6 452.1 773 453.9 775.3 452.3 777.7 452.6 780.1 452.2 782.4 453.3 784.8 452 787.2 453.5 789.6 452.8 791.9 452.9 794.3 453.1 796.7 452.9 799 452.3 801.4 454.6 803.8 453 806.2 453.4 808.5 453.3 810.9 454.6 813.3 453.9 815.7 452.3 818 454.7 820.4 453.2 822.8 453.5 825.1 453.1 827.5 454.4 829.9 453.3 832.3 455 834.6 454.5 837 453.6 839.4 454.3 841.7 454.1 844.1 455.1 846.5 453.9 848.9 455.3 851.2 454.5 853.6 454.7 856 455 858.3 454.6 860.7 455.6 863.1 454.4 865.5 455.8 867.8 454.9 870.2 454.9 872.6 455.1 875 454.9 877.3 456 879.7 454.8 882.1 456.3 884.4 455.9 886.8 455.3 889.2 455.9 891.6 372 893.9 285.6 896.3 238.2 898.7 200.5 901 178.4 903.4 162.4 905.8 150.5 908.2 142 910.5 135.3 912.9 130.5 915.3 127.1 917.6 124.1 920 121.4 922.4 119.2 924.8 118.4 927.1 117.9 929.5 116.5 931.9 115.5 934.3 114.8 936.6 114 939 113.2 941.4 112.7 943.7 111.8 946.1 111.4 948.5 110.7 950.9 110.1 953.2 109.2 955.6 108.5 958 107.7 960.3 107.1 962.7 106.3 965.1 105.7 967.5 105.2 969.8 104.4 972.2 103.8 974.6 103 976.9 102.3 979.3 102.1 981.7 101.3 984.1 100 986.4 99.7 988.8 99.7 991.2 98.8 993.6 98.2 995.9 97.7 998.3 96.5 1000.7 96.4 1003 95.9 1005.4 95.1 1007.8 94.4 1010.2 94 1012.5 93.4 1014.9 93 1017.3 92.2 1019.6 92 1022 92.1 1024.4 91.3 1026.8 89.9 1029.1 90.2 1031.5 89.2 1033.9 88.5 1036.2 88.3 1038.6 87.7 1041 87.1 1043.4 155.6 1045.7 273.6 1048.1 351 1050.5 351 1052.9 367.2 1055.2 359.9 1057.6 356.9 1060 351 1062.3 351 1064.7 351 1067.1 351 1069.5 351 1071.8 351 1074.2 351 1076.6 351 1078.9 351 1081.3 351 1083.7 351 1086.1 351 1086.1 351 1087.9 351" fill="none"/>
</g>
<g transform="scale(1.0018)" font-size="10" stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<polyline points="95.5 19.5 95.5 655.5 1087.5 655.5 1087.5 19.5 95.5 19.5" fill="none"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg width="257mm" height="145mm" stroke-linejoin="round" stroke-width="28.222" version="1.1" viewBox="0 0 25700 14500" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="m12848 14509h-12858v-14519h25715v14519h-12857z" fill="#fff"/>
<path d="m13071 13572h-11522v-13093h23045v13093h-11523z" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1549 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m3644 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m5739 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m7834 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m9929 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m12024 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m14118 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m16213 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m18308 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m20403 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m22498 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 478v13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 13571h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 10952h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 8333h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 5715h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 3096h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 478h-23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1549 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1549 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m3644 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m3644 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m5739 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m5739 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m7834 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m7834 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m9929 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m9929 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m12024 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m12024 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m14118 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m14118 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m16213 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m16213 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m18308 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m18308 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m20403 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m20403 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m22498 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m22498 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m24594 13721v-150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1549 13571h23045" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 13571h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 13571h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 10952h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 10952h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 8333h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 8333h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 5715h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 5715h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 3096h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 3096h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 478h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1399 478h150" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m1549 13571v-13093" fill="none" stroke="#b3b3b3" stroke-linejoin="round"/>
<path d="m5967 10952 2870-583 2971-1300 1579-736 1393-583 2512-1298 2114-1320 2070-1299" fill="none" stroke="#ffd320" stroke-linejoin="round" stroke-width="80"/>
<path d="m5842 10827 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m5842 10827 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m8712 10244 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m8712 10244 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m11683 8944 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m11683 8944 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m13262 8208 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m13262 8208 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m14655 7625 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m14655 7625 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m17167 6327 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m17167 6327 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m19281 5007 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m19281 5007 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m21351 3708 125 250 125-250h-250z" fill="#ffd320"/>
<path d="m21351 3708 125 250 125-250h-250z" fill="none" stroke="#ffd320" stroke-linejoin="round"/>
<path d="m1549 10952h2095 2095 228l1867-583h1003l1092-737 1879-563 216-736h1363l731-583h662l1433-736 1079-562 1016-737 1098-583 997-737 1073-562 1022-737" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m1424 10952 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m1424 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m3519 10952 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m3519 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m5614 10952 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m5614 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m5842 10952 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m5842 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m7709 10369 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m7709 10369 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m8712 10369 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m8712 10369 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m9804 9632 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m9804 9632 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m11683 9069 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m11683 9069 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m11899 8333 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m11899 8333 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m13262 8333 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m13262 8333 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m13993 7750 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m13993 7750 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m14655 7750 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m14655 7750 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m16088 7014 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m16088 7014 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m17167 6452 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m17167 6452 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m18183 5715 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m18183 5715 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m19281 5132 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m19281 5132 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m20278 4395 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m20278 4395 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m21351 3833 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m21351 3833 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m22373 3096 125 125 125-125-125-125-125 125z" fill="#ff420e"/>
<path d="m22373 3096 125 125 125-125-125-125-125 125z" fill="none" stroke="#ff420e" stroke-linejoin="round"/>
<path d="m1549 11688h2095 2095l228-736h1867l1003-583h1092l1879-1300h216l1363-736h731l662-583h1433l1079-1298h1016l1098-1320h997l1073-1299h1022" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m1424 11688 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m1424 11688 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m3519 11688 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m3519 11688 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m5614 11688 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m5614 11688 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m5842 10952 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m5842 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m7709 10952 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m7709 10952 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m8712 10369 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m8712 10369 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m9804 10369 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m9804 10369 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m11683 9069 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m11683 9069 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m11899 9069 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m11899 9069 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m13262 8333 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m13262 8333 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m13993 8333 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m13993 8333 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m14655 7750 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m14655 7750 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m16088 7750 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m16088 7750 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m17167 6452 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m17167 6452 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m18183 6452 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m18183 6452 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m19281 5132 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m19281 5132 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m20278 5132 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m20278 5132 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m21351 3833 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m21351 3833 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<path d="m22373 3833 125 125 125-125-125-125-125 125z" fill="#004586"/>
<path d="m22373 3833 125 125 125-125-125-125-125 125z" fill="none" stroke="#004586" stroke-linejoin="round"/>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1450" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">0</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="3148" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">10000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="5243" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">20000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7338" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">30000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="9433" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">40000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="11528" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">50000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="13623" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">60000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15718" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">70000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="17813" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">80000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="19908" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">90000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="21903" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">100000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="23999" y="14139"><tspan fill="rgb(0,0,0)" style="white-space:pre">110000</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1101" y="13692"><tspan fill="rgb(0,0,0)" style="white-space:pre">0</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="704" y="11073"><tspan fill="rgb(0,0,0)" style="white-space:pre">256</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="704" y="8454"><tspan fill="rgb(0,0,0)" style="white-space:pre">512</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="704" y="5835"><tspan fill="rgb(0,0,0)" style="white-space:pre">768</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="505" y="3216"><tspan fill="rgb(0,0,0)" style="white-space:pre">1024</tspan></tspan></tspan></text>
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="505" y="598"><tspan fill="rgb(0,0,0)" style="white-space:pre">1280</tspan></tspan></tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,416 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/timer.h"
#include "hardware/pwm.h"
#include <pico/divider.h>
#include "quadrature_encoder_substep.pio.h"
//
// ---- quadrature encoder interface with sub-step accuracy
//
// At low speeds, or high sample rates, a quadrature encoder can produce a small
// number of steps per sample, which makes any speed estimate made from those
// counts to be very noisy.
//
// This code uses a PIO program to count steps like the standard quadrature
// encoder example, but also mark the timestamp of the last step transition,
// which then allows the sampling code to measure the actual speed by computing
// the time passed between transitions and the "distance" traveled. See
// README.md for more details
// this section is an optional DC motor control code to help test an encoder
// attached to a DC motor (and calibrate phase sizes)
const int dir_pin = 5;
const int pwm_pin = 7;
static void set_pwm(float value)
{
int ivalue = value * 6250;
if (ivalue < 0) {
gpio_put(dir_pin, true);
pwm_set_gpio_level(pwm_pin, 6250+ivalue);
} else {
gpio_put(dir_pin, false);
pwm_set_gpio_level(pwm_pin, ivalue);
}
}
static void init_pwm(void)
{
gpio_init(dir_pin);
gpio_set_dir(dir_pin, true);
gpio_init(pwm_pin);
gpio_set_dir(pwm_pin, true);
pwm_config cfg = pwm_get_default_config();
pwm_config_set_clkdiv_int(&cfg, 1);
pwm_config_set_wrap(&cfg, 6250);
pwm_init(pwm_gpio_to_slice_num(pwm_pin), &cfg, true);
gpio_set_function(pwm_pin, GPIO_FUNC_PWM);
set_pwm(0);
}
// the quadrature encoder code starts here
typedef struct substep_state_t {
// configuration data:
uint calibration_data[4]; // relative phase sizes
uint clocks_per_us; // save the clk_sys frequency in clocks per us
uint idle_stop_samples; // after these samples without transitions, assume the encoder is stopped
PIO pio;
uint sm;
// internal fields to keep track of the previous state:
uint prev_trans_pos, prev_trans_us;
uint prev_step_us;
uint prev_low, prev_high;
uint idle_stop_sample_count;
int speed_2_20;
int stopped;
// output of the encoder update function:
int speed; // estimated speed in substeps per second
uint position; // estimated position in substeps
uint raw_step; // raw step count
} substep_state_t;
// internal helper functions (not to be used by user code)
static void read_pio_data(substep_state_t *state, uint *step, uint *step_us, uint *transition_us, int *forward)
{
int cycles;
// get the raw data from the PIO state machine
quadrature_encoder_substep_get_counts(state->pio, state->sm, step, &cycles, step_us);
// when the PIO program detects a transition, it sets cycles to either zero
// (when step is incrementing) or 2^31 (when step is decrementing) and keeps
// decrementing it on each 13 clock loop. We can use this information to get
// the time and direction of the last transition
if (cycles < 0) {
cycles = -cycles;
*forward = 1;
} else {
cycles = 0x80000000 - cycles;
*forward = 0;
}
*transition_us = *step_us - ((cycles * 13) / state->clocks_per_us);
}
// get the sub-step position of the start of a step
static uint get_step_start_transition_pos(substep_state_t *state, uint step)
{
return ((step << 6) & 0xFFFFFF00) | state->calibration_data[step & 3];
}
// compute speed in "sub-steps per 2^20 us" from a delta substep position and
// delta time in microseconds. This unit is cheaper to compute and use, so we
// only convert to "sub-steps per second" once per update, at most
static int substep_calc_speed(int delta_substep, int delta_us)
{
return ((int64_t) delta_substep << 20) / delta_us;
}
// main functions to be used by user code
// initialize the substep state structure and start PIO code
static void substep_init_state(PIO pio, int sm, int pin_a, substep_state_t *state)
{
int forward;
// set all fields to zero by default
memset(state, 0, sizeof(substep_state_t));
// initialize the PIO program (and save the PIO reference)
state->pio = pio;
state->sm = sm;
quadrature_encoder_substep_program_init(pio, sm, pin_a);
// start with equal phase size calibration
state->calibration_data[0] = 0;
state->calibration_data[1] = 64;
state->calibration_data[2] = 128;
state->calibration_data[3] = 192;
state->idle_stop_samples = 3;
// start "stopped" so that we don't use stale data to compute speeds
state->stopped = 1;
// cache the PIO cycles per us
state->clocks_per_us = (clock_get_hz(clk_sys) + 500000) / 1000000;
// initialize the "previous state"
read_pio_data(state, &state->raw_step, &state->prev_step_us, &state->prev_trans_us, &forward);
state->position = get_step_start_transition_pos(state, state->raw_step) + 32;
}
// read the PIO data and update the speed / position estimate
static void substep_update(substep_state_t *state)
{
uint step, step_us, transition_us, transition_pos, low, high;
int forward, speed_high, speed_low;
// read the current encoder state from the PIO
read_pio_data(state, &step, &step_us, &transition_us, &forward);
// from the current step we can get the low and high boundaries in substeps
// of the current position
low = get_step_start_transition_pos(state, step);
high = get_step_start_transition_pos(state, step + 1);
// if we were not stopped, but the last transition was more than
// "idle_stop_samples" ago, we are stopped now
if (step == state->raw_step)
state->idle_stop_sample_count++;
else
state->idle_stop_sample_count = 0;
if (!state->stopped && state->idle_stop_sample_count >= state->idle_stop_samples) {
state->speed = 0;
state->speed_2_20 = 0;
state->stopped = 1;
}
// when we are at a different step now, there is certainly a transition
if (state->raw_step != step) {
// the transition position depends on the direction of the move
transition_pos = forward ? low : high;
// if we are not stopped, that means there is valid previous transition
// we can use to estimate the current speed
if (!state->stopped)
state->speed_2_20 = substep_calc_speed(transition_pos - state->prev_trans_pos, transition_us - state->prev_trans_us);
// if we have a transition, we are not stopped now
state->stopped = 0;
// save the timestamp and position of this transition to use later to
// estimate speed
state->prev_trans_pos = transition_pos;
state->prev_trans_us = transition_us;
}
// if we are stopped, speed is zero and the position estimate remains
// constant. If we are not stopped, we have to update the position and speed
if (!state->stopped) {
// although the current step doesn't give us a precise position, it does
// give boundaries to the position, which together with the last
// transition gives us boundaries for the speed value. This can be very
// useful especially in two situations:
// - we have been stopped for a while and start moving quickly: although
// we only have one transition initially, the number of steps we moved
// can already give a non-zero speed estimate
// - we were moving but then stop: without any extra logic we would just
// keep the last speed for a while, but we know from the step
// boundaries that the speed must be decreasing
// if there is a transition between the last sample and now, and that
// transition is closer to now than the previous sample time, we should
// use the slopes from the last sample to the transition as these will
// have less numerical issues and produce a tighter boundary
if (state->prev_trans_us > state->prev_step_us &&
(int)(state->prev_trans_us - state->prev_step_us) > (int)(step_us - state->prev_trans_us)) {
speed_high = substep_calc_speed(state->prev_trans_pos - state->prev_low, state->prev_trans_us - state->prev_step_us);
speed_low = substep_calc_speed(state->prev_trans_pos - state->prev_high, state->prev_trans_us - state->prev_step_us);
} else {
// otherwise use the slopes from the last transition to now
speed_high = substep_calc_speed(high - state->prev_trans_pos, step_us - state->prev_trans_us);
speed_low = substep_calc_speed(low - state->prev_trans_pos, step_us - state->prev_trans_us);
}
// make sure the current speed estimate is between the maximum and
// minimum values obtained from the step slopes
if (state->speed_2_20 > speed_high)
state->speed_2_20 = speed_high;
if (state->speed_2_20 < speed_low)
state->speed_2_20 = speed_low;
// convert the speed units from "sub-steps per 2^20 us" to "sub-steps
// per second"
state->speed = (state->speed_2_20 * 62500LL) >> 16;
// estimate the current position by applying the speed estimate to the
// most recent transition
state->position = state->prev_trans_pos + (((int64_t)state->speed_2_20 * (step_us - transition_us)) >> 20);
// make sure the position estimate is between "low" and "high", as we
// can be sure the actual current position must be in this range
if ((int)(state->position - high) > 0)
state->position = high;
else if ((int)(state->position - low) < 0)
state->position = low;
}
// save the current values to use on the next sample
state->prev_low = low;
state->prev_high = high;
state->raw_step = step;
state->prev_step_us = step_us;
}
// function to measure the difference between the different steps on the encoder
static void substep_calibrate_phases(PIO pio, uint sm)
{
#define sample_count 1024
//#define SHOW_ALL_SAMPLES
#ifdef SHOW_ALL_SAMPLES
static int result[sample_count];
int i;
#endif
int index, cycles, clocks_per_us, calib[4];
uint cur_us, last_us, step_us, step, last_step;
int64_t sum[4], total;
memset(sum, 0, sizeof(sum));
clocks_per_us = (clock_get_hz(clk_sys) + 500000) / 1000000;
// keep reading the PIO state in a tight loop to get all steps and use the
// transition measures of the PIO code to measure the time of each step
last_step = -10;
index = -10;
while (index < sample_count) {
quadrature_encoder_substep_get_counts(pio, sm, &step, &cycles, &step_us);
// wait until we have a transition
if (step == last_step)
continue;
// synchronize the index with the lower 2 bits of the current step
if (index < 0 && index > -4 && (step & 3) == 1)
index = 0;
// convert the "time since last transition" to an absolute microsecond
// timestamp
if (cycles > 0) {
printf("error: expected forward motion\n");
return;
}
cur_us = step_us + (cycles * 13) / clocks_per_us;
// if the index is already synchronized, use the step size
if (index >= 0) {
#ifdef SHOW_ALL_SAMPLES
result[index] = cur_us - last_us;
#endif
sum[(step - 1) & 3] += cur_us - last_us;
}
index++;
last_step = step;
last_us = cur_us;
}
#ifdef SHOW_ALL_SAMPLES
printf("full sample table:\n");
for (i = 0; i < sample_count; i++) {
printf("%d ", result[i]);
if ((i & 3) == 3)
printf("\n");
}
#endif
// scale the sizes to a total of 256 to be used as sub-steps
total = sum[0] + sum[1] + sum[2] + sum[3];
calib[0] = (sum[0] * 256 + total / 2) / total;
calib[1] = ((sum[0] + sum[1]) * 256 + total / 2) / total;
calib[2] = ((sum[0] + sum[1] + sum[2]) * 256 + total / 2) / total;
// print calibration information
printf("calibration command:\n\n");
printf("\tsubstep_set_calibration_data(&state, %d, %d, %d);\n\n",
calib[0], calib[1], calib[2]);
}
// set the phase size calibration, use the "substep_calibrate_phases" function
// to get the values. Many encoders (especially low cost ones) have phases that
// don't have the same size. To get good substep accuracy, the code should know
// about this. This is specially important at low speeds with encoders that have
// big phase size differences
static void substep_set_calibration_data(substep_state_t *state, int step0, int step1, int step2)
{
state->calibration_data[0] = 0;
state->calibration_data[1] = step0;
state->calibration_data[2] = step1;
state->calibration_data[3] = step2;
}
int main(void)
{
substep_state_t state;
// base pin to connect the A phase of the encoder. the B phase must be
// connected to the next pin
const uint PIN_A = 2;
stdio_init_all();
stdio_set_translate_crlf(&stdio_usb, false);
PIO pio = pio0;
const uint sm = 0;
pio_add_program(pio, &quadrature_encoder_substep_program);
substep_init_state(pio, sm, PIN_A, &state);
// example calibration code, uncomment to calibrate the encoder:
// // - turn on a DC motor at 50% PWM
// init_pwm();
// set_pwm(-0.5);
// // - wait for the motor to reach a reasonably stable speed
// sleep_ms(2000);
// // - run the phase size calibration code
// substep_calibrate_phases(pio, sm);
// // - stop the motor
// set_pwm(0);
// replace this with the output of the calibration function
substep_set_calibration_data(&state, 64, 128, 192);
uint last_position = 0;
int last_speed = 0;
uint last_raw_step = 0;
while (1) {
// read the PIO and update the state data
substep_update(&state);
if (last_position != state.position || last_speed != state.speed || last_raw_step != state.raw_step) {
// print out the result
printf("pos: %-10d speed: %-10d raw_steps: %-10d\n", state.position, state.speed, state.raw_step);
last_position = state.position;
last_speed = state.speed;
last_raw_step = state.raw_step;
}
// run at roughly 100Hz
sleep_ms(10);
}
}

View File

@ -0,0 +1,205 @@
;
; Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
; quadrature_encoder_substep: reads a quadrature encoder with no CPU
; intervention and provides the current position on request.
;
; the "substep" version uses not only the step counts, but also the timing of
; the steps to compute the current speed. See README.md for details
.program quadrature_encoder_substep
.origin 0
; the PIO code counts steps like the standard quadrature encoder code, but also
; keeps track of the time passed since the last transition. That allows the C
; code to build a good estimate of a fractional step position based on the
; lastest speed and time passed
;
; since it needs to push two values, it only pushes new data when the FIFO has
; enough space to hold both values. Otherwise it could either stall or go out
; of sync
;
; because we need to count the time passed, all loops must take the same number
; of cycles and there are delays added to the fastest branches to make sure it
; always takes 13 cycles per loop (e.g., sysclk 133MHz, max step rate = ~10.2
; Msteps/sec)
; push the step count and transition clock count to the RX FIFO (using
; auto push). This is reached by the "MOV PC, ~STATUS" instruction when
; status is all 1 (meaning fifo has space for this push). It also may
; execute once at program start, but that has little effect
IN X, 32
IN Y, 32
update_state:
; build the state by using 2 bits from the negated previous state of the
; pins and the new 2 bit state of the pins
OUT ISR, 2
IN PINS, 2
MOV OSR, ~ISR
; use the jump table to update the step count accordingly
MOV PC, OSR
decrement:
; decrement the step count
JMP Y--, decrement_cont
decrement_cont:
; when decrementing, X is set to 2^31, when incrementing it is set to
; zero. That way the C code can infer in which direction the last
; transition was taken and how long ago
SET X, 1
MOV X, ::X
; after incrementing or decrementing, continue to "check_fifo"
check_fifo:
.wrap_target
; on each iteration we decrement X to count the number of loops since
; the last transition
JMP X--, check_fifo_cont
check_fifo_cont:
; push data or continue, depending on the state of the fifo
MOV PC, ~STATUS
increment:
; the PIO does not have a increment instruction, so to do that we do a
; negate, decrement, negate sequence
MOV Y, ~Y
JMP Y--, increment_cont
increment_cont:
MOV Y, ~Y
; reset X to zero when incrementing
SET X, 0
; wrap above to check the fifo state
.wrap
invalid:
; this is just a placeholder to document what the code does on invalid
; transitions, where the two phases change at the same time. We don't do
; anything special, but the encoder should note generate these invalid
; transitions anyway
JMP update_state
; this jump table starts at address 16 and is accessed by the
; "MOV PC, OSR" instruction above, that loads the PC with the state on
; the lower 4 bits and the 5th bit on. The delays here extend the faster
; branches to take the same time as the slower branches
JMP invalid
JMP increment [0]
JMP decrement [1]
JMP check_fifo [4]
JMP decrement [1]
JMP invalid
JMP check_fifo [4]
JMP increment [0]
JMP increment [0]
JMP check_fifo [4]
JMP invalid
JMP decrement [1]
JMP check_fifo [4]
JMP decrement [1]
JMP increment [0]
; this instruction should be usually reached by the "MOV PC, ~STATUS"
; instruction above when the status is zero, which means that the fifo
; has data and we don't want to push more data. This can also be reached
; on an invalid state transition, which should not happen. Even if it
; happens, it should be a transient state and the only side effect is
; that we'll call update_state twice in a row
JMP update_state [1]
% c-sdk {
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"
// "substep" version low-level interface
//
// note: user code should use the high level functions in quadrature_encoder.c
// and not call these directly
// initialize the PIO state and the substep_state_t structure that keeps track
// of the encoder state
static inline void quadrature_encoder_substep_program_init(PIO pio, uint sm, uint pin_A)
{
uint pin_state, position, ints;
pio_sm_set_consecutive_pindirs(pio, sm, pin_A, 2, false);
gpio_pull_up(pin_A);
gpio_pull_up(pin_A + 1);
pio_sm_config c = quadrature_encoder_substep_program_get_default_config(0);
sm_config_set_in_pins(&c, pin_A); // for WAIT, IN
// shift to left, auto-push at 32 bits
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_shift(&c, true, false, 32);
// don't join FIFO's
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE);
// always run at sysclk, to have the maximum possible time resolution
sm_config_set_clkdiv(&c, 1.0);
pio_sm_init(pio, sm, 0, &c);
// set up status to be rx_fifo < 1
pio->sm[sm].execctrl = ((pio->sm[sm].execctrl & 0xFFFFFF80) | 0x12);
// init the state machine according to the current phase. Since we are
// setting the state running PIO instructions from C state, the encoder may
// step during this initialization. This should not be a problem though,
// because as long as it is just one step, the state machine will update
// correctly when it starts. We disable interrupts anyway, to be safe
ints = save_and_disable_interrupts();
pin_state = (gpio_get_all() >> pin_A) & 3;
// to setup the state machine, we need to set the lower 2 bits of OSR to be
// the negated pin state
pio_sm_exec(pio, sm, pio_encode_set(pio_y, ~pin_state));
pio_sm_exec(pio, sm, pio_encode_mov(pio_osr, pio_y));
// also set the Y (current step) so that the lower 2 bits of Y have a 1:1
// mapping to the current phase (input pin state). That simplifies the code
// to compensate for differences in encoder phase sizes:
switch (pin_state) {
case 0: position = 0; break;
case 1: position = 3; break;
case 2: position = 1; break;
case 3: position = 2; break;
}
pio_sm_exec(pio, sm, pio_encode_set(pio_y, position));
pio_sm_set_enabled(pio, sm, true);
restore_interrupts(ints);
}
static inline void quadrature_encoder_substep_get_counts(PIO pio, uint sm, uint *step, int *cycles, uint *us)
{
int i, pairs;
uint ints;
pairs = pio_sm_get_rx_fifo_level(pio, sm) >> 1;
// read all data with interrupts disabled, so that there can not be a
// big time gap between reading the PIO data and the current us
ints = save_and_disable_interrupts();
for (i = 0; i < pairs + 1; i++) {
*cycles = pio_sm_get_blocking(pio, sm);
*step = pio_sm_get_blocking(pio, sm);
}
*us = time_us_32();
restore_interrupts(ints);
}
%}

View File

@ -7,9 +7,13 @@
.program ws2812
.side_set 1
.define public T1 2
.define public T2 5
.define public T3 3
; The following constants are selected for broad compatibility with WS2812,
; WS2812B, and SK6812 LEDs. Other constants may support higher bandwidths for
; specific LEDs, such as (7,10,8) for WS2812B LEDs.
.define public T1 3
.define public T2 3
.define public T3 4
.lang_opt python sideset_init = pico.PIO.OUT_HIGH
.lang_opt python out_init = pico.PIO.OUT_HIGH
@ -49,9 +53,9 @@ static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
.program ws2812_parallel
.define public T1 2
.define public T2 5
.define public T3 3
.define public T1 3
.define public T2 3
.define public T3 4
.wrap_target
out x, 32

View File

@ -488,6 +488,9 @@ static void usb_handle_buff_status() {
* @brief USB interrupt handler
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/// \tag::isr_setup_packet[]
void isr_usbctrl(void) {
// USB interrupt handler
@ -520,6 +523,9 @@ void isr_usbctrl(void) {
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
}
}
#ifdef __cplusplus
}
#endif
/**
* @brief EP0 in transfer complete. Either finish the SET_ADDRESS process, or receive a zero