0%

RP2040应用指南

PIO相关

1
2
3
4
5
6
.program squarewave
set pindirs, 1 ; Set pin to output
again:
set pins, 1 [1] ; Drive pin high and then delay for one cycle
set pins, 0 ; Drive pin low
jmp again ; Set PC to label `again`

OpenOCD烧写调试

1
~$ ../configure --enable-cmsis-dap --enable-sysfsgpio --enable-imx_gpio --enable-bcm2835gpio  --enable-xds110 --enable-ftdi --enable-stlink
  • 添加支持Pyua PY25Q32H nor flash的支持
1
2
3
4
5
6
7
8
9
10
11
12
13
~ openocd$ git diff
diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c
index bf654f9f6..ac3e1e069 100644
--- a/src/flash/nor/spi.c
+++ b/src/flash/nor/spi.c
@@ -184,6 +184,7 @@ const struct flash_device flash_devices[] = {
FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000),
FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000),
FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000),
+ FLASH_ID("pyua py25q32h", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00162085, 0x100, 0x10000, 0x400000),

/* FRAM, no erase commands, no write page or sectors */

  • 烧写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
~$ openocd -f interface/ftdi/ft232h-module-swd.cfg  -f target/rp2040.cfg -c "program blink.elf verify reset exit"
Open On-Chip Debugger 0.12.0+dev-01369-gb388f4805 (2023-11-04-10:01)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : FTDI SWD mode enabled
swd
Warn : Transport "swd" was already selected
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Warn : An adapter speed is not selected in the init scripts. OpenOCD will try to run the adapter at very low speed (100 kHz).
Warn : To remove this warnings and achieve reasonable communication speed with the target, set "adapter speed" or "jtag_rclk" in the init scripts.
Info : clock speed 100 kHz
Info : SWD DPIDR 0x0bc12477, DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477, DLPIDR 0x10000001
Info : [rp2040.core0] Cortex-M0+ r0p1 processor detected
Info : [rp2040.core0] target has 4 breakpoints, 2 watchpoints
Info : [rp2040.core1] Cortex-M0+ r0p1 processor detected
Info : [rp2040.core1] target has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
Warn : [rp2040.core1] target was in unknown state when halt was requested
[rp2040.core0] halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
[rp2040.core1] halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
** Programming Started **
Info : Found flash device 'win w25q16jv' (ID 0x001540ef)
Info : RP2040 B0 Flash Probe: 2097152 bytes @0x10000000, in 32 sectors

Info : Padding image section 1 at 0x10002190 with 112 bytes (bank write end alignment)
Warn : Adding extra erase range, 0x10002200 .. 0x1000ffff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked

UF2文件方式烧写

  • pico-examples里的工程编译完成后,都会生成.uf2的文件,按住BOOTSEL上电进入到UF2模式,复制粘贴.uf2进去,就能烧写成功。

  • 或者使用arduino-pico里的工具烧写,如下:

1
python3 -I /home/michael/.arduino15/packages/rp2040/hardware/rp2040/3.6.2/tools/uf2conv.py --serial /dev/ttyACM0 --family RP2040 --deploy /tmp/arduino_build_788465/shift.ino.uf2

学习理解tinyusb+pico-sdk编译工程结构

  • TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
~$ git clone https://github.com/hathach/tinyusb

~$ cd tinyusb
~$ tinyusb$ tree -L 2 -d
.
├── docs
│   ├── assets
│   ├── contributing
│   ├── info
│   └── reference
├── examples
│   ├── build
│   ├── device
│   ├── dual
│   ├── host
│   └── typec
├── hw
│   ├── bsp
│   └── mcu
├── lib
│   ├── embedded-cli
│   ├── fatfs
│   ├── networking
│   └── SEGGER_RTT
├── src
│   ├── class
│   ├── common
│   ├── device
│   ├── host
│   ├── osal
│   ├── portable
│   └── typec
├── test
│   ├── fuzz
│   ├── hil
│   └── unit-test
└── tools
├── cmake
├── codespell
├── make
└── usb_drivers

37 directories


  • 下面以tinyusb/examples/device/cdc_msc的工程为例。
1
2
3
4
5
6
7
8
9
10
11
12
13
tinyusb/examples/device/cdc_msc$ tree
.
├── CMakeLists.txt
├── Makefile
├── skip.txt
└── src
├── main.c
├── msc_disk.c
├── tusb_config.h
└── usb_descriptors.c

2 directories, 7 files

  • 分析CMakeLists.txt文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
tinyusb/examples/device/cdc_msc$ cat -n CMakeLists.txt
1 cmake_minimum_required(VERSION 3.17)
2 set_property(GLOBAL PROPERTY USE_FOLDERS ON) # 设置全局的属性,名为:USE_FOLDERS, 值为ON。
3
4 include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
5
6 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
7 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
8
9 project(${PROJECT} C CXX ASM)
10
11 # Checks this example is valid for the family and initializes the project
12 family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) # 定义在 family_support.cmake 内的函数。通过这里调用到tinyusb/hw/bsp/rp2040/family.cmake
13
14 # Espressif has its own cmake build system
15 if(FAMILY STREQUAL "espressif")
16 return()
17 endif()
18
19 add_executable(${PROJECT})
20
21 # Example source
22 target_sources(${PROJECT} PUBLIC
23 ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
24 ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
25 ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
26 )
27
28 # Example include
29 target_include_directories(${PROJECT} PUBLIC
30 ${CMAKE_CURRENT_SOURCE_DIR}/src
31 )
32
33 # Configure compilation flags and libraries for the example... see the corresponding function
34 # in hw/bsp/FAMILY/family.cmake for details.
35 family_configure_device_example(${PROJECT} noos) # 需要在family.cmake里扩展的函数。

  • 上面的CMakeLists.txt第4行引入其它的tinyusb/hw/bsp/family_support.cmake文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
tinyusb/hw/bsp$ cat family_support.cmake
include_guard(GLOBAL) # 防止重复include当前的文件。

include(CMakePrintHelpers) # Convenience functions for printing properties and variables, useful e.g. for debugging.

# TOP is path to root directory
set(TOP "${CMAKE_CURRENT_LIST_DIR}/../..") # 设置变量TOP的值。
get_filename_component(TOP ${TOP} ABSOLUTE) # cmake 内置的函数,获取`${TOP}`完全路径。

# Default to gcc
if (NOT DEFINED TOOLCHAIN)
set(TOOLCHAIN gcc)
endif ()

# FAMILY not defined, try to detect it from BOARD
if (NOT DEFINED FAMILY)
if (NOT DEFINED BOARD)
message(FATAL_ERROR "You must set a FAMILY variable for the build (e.g. rp2040, espressif).
You can do this via -DFAMILY=xxx on the cmake command line")
endif ()

# Find path contains BOARD
file(GLOB BOARD_PATH LIST_DIRECTORIES true
RELATIVE ${TOP}/hw/bsp
${TOP}/hw/bsp/*/boards/${BOARD}
)
if (NOT BOARD_PATH)
message(FATAL_ERROR "Could not detect FAMILY from BOARD=${BOARD}")
endif ()

# replace / with ; so that we can get the first element as FAMILY
string(REPLACE "/" ";" BOARD_PATH ${BOARD_PATH})
list(GET BOARD_PATH 0 FAMILY)
endif ()

if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
message(FATAL_ERROR "Family '${FAMILY}' is not known/supported")
endif()

if (NOT FAMILY STREQUAL rp2040)
# enable LTO if supported skip rp2040
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_SUPPORTED)
cmake_print_variables(IPO_SUPPORTED)
if (IPO_SUPPORTED)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
endif()

set(WARNING_FLAGS_GNU
-Wall
-Wextra
-Werror
[...]
)

set(WARNINGS_FLAGS_IAR "")

# Filter example based on only.txt and skip.txt
function(family_filter RESULT DIR)
get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

if (EXISTS "${DIR}/only.txt")
file(READ "${DIR}/only.txt" ONLYS)
# Replace newlines with semicolon so that it is treated as a list by CMake
string(REPLACE "\n" ";" ONLYS_LINES ${ONLYS})

# For each mcu
foreach(MCU IN LISTS FAMILY_MCUS)
# For each line in only.txt
foreach(_line ${ONLYS_LINES})
# If mcu:xxx exists for this mcu or board:xxx then include
if (${_line} STREQUAL "mcu:${MCU}" OR ${_line} STREQUAL "board:${BOARD}")
set(${RESULT} 1 PARENT_SCOPE)
return()
endif()
endforeach()
endforeach()

# Didn't find it in only file so don't build
set(${RESULT} 0 PARENT_SCOPE)

elseif (EXISTS "${DIR}/skip.txt")
file(READ "${DIR}/skip.txt" SKIPS)
# Replace newlines with semicolon so that it is treated as a list by CMake
string(REPLACE "\n" ";" SKIPS_LINES ${SKIPS})

# For each mcu
foreach(MCU IN LISTS FAMILY_MCUS)
# For each line in only.txt
foreach(_line ${SKIPS_LINES})
# If mcu:xxx exists for this mcu then skip
if (${_line} STREQUAL "mcu:${MCU}")
set(${RESULT} 0 PARENT_SCOPE)
return()
endif()
endforeach()
endforeach()

# Didn't find in skip file so build
set(${RESULT} 1 PARENT_SCOPE)
else()

# Didn't find skip or only file so build
set(${RESULT} 1 PARENT_SCOPE)
endif()
endfunction()


function(family_add_subdirectory DIR)
family_filter(SHOULD_ADD "${DIR}")
if (SHOULD_ADD)
add_subdirectory(${DIR})
endif()
endfunction()


function(family_get_project_name OUTPUT_NAME DIR)
get_filename_component(SHORT_NAME ${DIR} NAME)
set(${OUTPUT_NAME} ${TINYUSB_FAMILY_PROJECT_NAME_PREFIX}${SHORT_NAME} PARENT_SCOPE)
endfunction()


function(family_initialize_project PROJECT DIR)
# set output suffix to .elf (skip espressif and rp2040)
if(NOT FAMILY STREQUAL "espressif" AND NOT FAMILY STREQUAL "rp2040")
set(CMAKE_EXECUTABLE_SUFFIX .elf PARENT_SCOPE)
endif()

family_filter(ALLOWED "${DIR}")
if (NOT ALLOWED)
get_filename_component(SHORT_NAME ${DIR} NAME)
message(FATAL_ERROR "${SHORT_NAME} is not supported on FAMILY=${FAMILY}")
endif()
endfunction()


#-------------------------------------------------------------
# Common Target Configure
# Most families use these settings except rp2040 and espressif
#-------------------------------------------------------------

# Add RTOS to example
function(family_add_rtos TARGET RTOS)
if (RTOS STREQUAL "freertos")
# freertos config
if (NOT TARGET freertos_config)
add_library(freertos_config INTERFACE)
target_include_directories(freertos_config INTERFACE ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${FAMILY}/FreeRTOSConfig)
# add board definition to freertos_config mostly for SystemCoreClock
target_link_libraries(freertos_config INTERFACE board_${BOARD})
endif()

# freertos kernel
if (NOT TARGET freertos_kernel)
add_subdirectory(${TOP}/lib/FreeRTOS-Kernel ${CMAKE_BINARY_DIR}/lib/freertos_kernel)
endif ()

target_link_libraries(${TARGET} PUBLIC freertos_kernel)
endif ()
endfunction()


# Add common configuration to example
function(family_configure_common TARGET RTOS)
family_add_rtos(${TARGET} ${RTOS})

string(TOUPPER ${BOARD} BOARD_UPPER)
string(REPLACE "-" "_" BOARD_UPPER ${BOARD_UPPER})
target_compile_definitions(${TARGET} PUBLIC
BOARD_${BOARD_UPPER}
)

# run size after build
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${TARGET}>
)

# Add warnings flags
target_compile_options(${TARGET} PUBLIC ${WARNING_FLAGS_${CMAKE_C_COMPILER_ID}})

# Generate linker map file
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_link_options(${TARGET} PUBLIC "LINKER:-Map=$<TARGET_FILE:${TARGET}>.map")
endif()

# ETM Trace option
if (TRACE_ETM STREQUAL "1")
target_compile_definitions(${TARGET} PUBLIC TRACE_ETM)
endif ()

# LOGGER option
if (DEFINED LOGGER)
target_compile_definitions(${TARGET} PUBLIC LOGGER_${LOGGER})

# Add segger rtt to example
if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt")
if (NOT TARGET segger_rtt)
add_library(segger_rtt STATIC ${TOP}/lib/SEGGER_RTT/RTT/SEGGER_RTT.c)
target_include_directories(segger_rtt PUBLIC ${TOP}/lib/SEGGER_RTT/RTT)
#target_compile_definitions(segger_rtt PUBLIC SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL)
endif()
target_link_libraries(${TARGET} PUBLIC segger_rtt)
endif ()
endif ()
endfunction()


# Add tinyusb to example
function(family_add_tinyusb TARGET OPT_MCU RTOS)
# tinyusb target is built for each example since it depends on example's tusb_config.h
set(TINYUSB_TARGET_PREFIX ${TARGET}-)
add_library(${TARGET}-tinyusb_config INTERFACE)

# path to tusb_config.h
target_include_directories(${TARGET}-tinyusb_config INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUSB_MCU=${OPT_MCU})

if (DEFINED LOG)
target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUSB_DEBUG=${LOG})
if (LOG STREQUAL "4")
# no inline for debug level 4
target_compile_definitions(${TARGET}-tinyusb_config INTERFACE TU_ATTR_ALWAYS_INLINE=)
endif ()
endif()

if (RTOS STREQUAL "freertos")
target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUSB_OS=OPT_OS_FREERTOS)
endif ()

# tinyusb's CMakeList.txt
add_subdirectory(${TOP}/src ${CMAKE_CURRENT_BINARY_DIR}/tinyusb)

if (RTOS STREQUAL "freertos")
# link tinyusb with freeRTOS kernel
target_link_libraries(${TARGET}-tinyusb PUBLIC freertos_kernel)
endif ()

# use max3421 as host controller
if (MAX3421_HOST STREQUAL "1")
target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUH_MAX3421=1)
target_sources(${TARGET}-tinyusb PUBLIC
${TOP}/src/portable/analog/max3421/hcd_max3421.c
)
endif ()

endfunction()


# Add bin/hex output
function(family_add_bin_hex TARGET)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.bin
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.hex
VERBATIM)
endfunction()


#----------------------------------
# Example Target Configure (Default rule)
# These function can be redefined in FAMILY/family.cmake
#----------------------------------

function(family_configure_example TARGET RTOS)
# empty function, should be redefined in FAMILY/family.cmake
endfunction()

# Configure device example with RTOS
function(family_configure_device_example TARGET RTOS)
family_configure_example(${TARGET} ${RTOS})
endfunction()


# Configure host example with RTOS
function(family_configure_host_example TARGET RTOS)
family_configure_example(${TARGET} ${RTOS})
endfunction()


# Configure host + device example with RTOS
function(family_configure_dual_usb_example TARGET RTOS)
family_configure_example(${TARGET} ${RTOS})
endfunction()

function(family_example_missing_dependency TARGET DEPENDENCY)
message(WARNING "${DEPENDENCY} submodule needed by ${TARGET} not found, please run 'python tools/get_deps.py ${DEPENDENCY}' to fetch it")
endfunction()

#----------------------------------
# RPI specific: refactor later
#----------------------------------
function(family_add_default_example_warnings TARGET)
target_compile_options(${TARGET} PUBLIC
-Wall
-Wextra
[...]
)

if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
target_link_options(${TARGET} PUBLIC "LINKER:--no-warn-rwx-segments")
endif()

# GCC 10
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)
target_compile_options(${TARGET} PUBLIC -Wconversion)
endif()
[...]
endfunction()

#----------------------------------
# Flashing target
#----------------------------------

# Add flash pycod target
function(family_flash_pyocd TARGET)
if (NOT DEFINED PYOC)
set(PYOCD pyocd)
endif ()

add_custom_target(${TARGET}-pyocd
DEPENDS ${TARGET}
COMMAND ${PYOCD} flash -t ${PYOCD_TARGET} $<TARGET_FILE:${TARGET}>
)
endfunction()


function(family_flash_dfu_util TARGET OPTION)
if (NOT DEFINED DFU_UTIL)
set(DFU_UTIL dfu-util)
endif ()

add_custom_target(${TARGET}-dfu-util
DEPENDS ${TARGET}
COMMAND ${DFU_UTIL} -R -d ${DFU_UTIL_VID_PID} -a 0 -D $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.bin
VERBATIM
)
endfunction()

#----------------------------------
# Family specific
#----------------------------------

# family specific: can override above functions
include(${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
# 这里调用不同的BSP或者MCU的目录的`cmake`文件,以rp2040为例是:tinyusb/hw/bsp/rp2040/family.cmake

if (NOT FAMILY_MCUS)
set(FAMILY_MCUS ${FAMILY})
endif()

# if use max3421 as host controller, expand FAMILY_MCUS to include max3421
if (MAX3421_HOST STREQUAL "1")
set(FAMILY_MCUS ${FAMILY_MCUS} MAX3421)
endif ()

# save it in case of re-inclusion
set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "")

ta

  • TinyUSB是一个嵌入式系统下开源跨平台的USB协议栈,以RP2040为例,它的开发实现是要依赖于pico-sdk的。

  • 编译工程

1
2
3
4
~ examples/device/video_capture$ mkdir build && cd build
~ examples/device/video_capture/build $
~ examples/device/video_capture/build $ cmake -DFAMILY=rp2040 -DPICO_SDK_PATH=/home/michael/3TB-DISK/RaspberryPi/RP2040/pico-sdk/ ../
~ examples/device/video_capture/build $ openocd -f interface/ftdi/ft232h-module-swd.cfg -f target/rp2040.cfg -c "program video_capture.elf verify reset exit"

使用TFT_eSPI(ardion)驱动ili9341 16bit并口屏

安装rp2040 bsp支持

  • 安装第三方的arduino-pico库,让Arduino IDE可以支持rp2040板子。
  • 首先在Arduino IDE -> File -> Preference -> Additional Boards Manager URLs:添加下面的链接:
1
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
  • 再打开Board Manager进行联网更新,搜索pico并且安装Raspberry Pi Pico/RP2040的包。

配置TFT_eSPI

  • 打开已经预定义好的文件:~/Arduino/libraries/TFT_eSPI/User_Setups/Setup107_RP2040_ILI9341_16bit_parallel.h,把屏幕与RP2040按照文件的线序进行连接。

  • 再打开~/Arduino/libraries/TFT_eSPI/User_Setups/User_Setup_Select.h,只打开上面这一个文件的注释。

1
#include <User_Setups/Setup107_RP2040_ILI9341_16bit_parallel.h>
  • 选择打开一个TFT_eSPI内置的测试工程。这里使用的是官方的板子,就选择Tools -> Boards -> Rasperry Pi RP2040 Boards -> Rasperry Pi Pico. 编译上传就可以看到结果,烧写过程中有可能需要手动复位BOOTSEL按键。

74HC565N Daisy-chaining测试

RP2040 74HC565N(1) 74HC565N(2) Logic Probe
GPIO0 STCP STCP
GPIO1 SHCP SHCP
GPIO2 DS
VCC VCC VCC
VCC MR MR
GND GND GND
GND QE QE
Q7S DS
Q0 D00
Q1 D01
Q2 D02
Q3 D03
Q4 D04
Q5 D05
Q6 D06
Q7 D07
Q0 D08
Q1 D09
Q2 D10
Q3 D11
Q4 D12
Q5 D13
Q6 D14
Q7 D15
  • 按照上面表格接连,在Arduino里烧写下面的测试代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int latchPin = 0;      // Latch pin of 74HC595 is connected to Digital pin 5 STCP storage clock pin
int clockPin = 1; // Clock pin of 74HC595 is connected to Digital pin 6 SHCP shift clock pin
int dataPin = 2; // Data pin of 74HC595 is connected to Digital pin 4
byte leds = 0;
short aa = 0xf3;
#define TOTAL_SHIFT_PINS 16

void setup()
{
// Set all the pins of 74HC595 as OUTPUT
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}


void loop()
{
leds = 0; // Initially turns all the LEDs off, by giving the variable 'leds' the value 0
updateShiftRegister();
delay(500);

for (int i = 0; i < TOTAL_SHIFT_PINS; i++) // Turn all the LEDs ON one by one.
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, aa);
digitalWrite(latchPin, HIGH);
delay(100);
}
}


/*
* updateShiftRegister() - This function sets the latchPin to low,
* then calls the Arduino function 'shiftOut' to shift out contents
* of variable 'leds' in the shift register before putting the 'latchPin' high again.
**/
void updateShiftRegister()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
  • 如果使用逻辑分析仪抓取到parallel协议解析出来也是aa=0xf3,就是工作正常的。

使用pico-sdk驱动双屏

  • 这里使用GPIOs bit-banging的方式驱动两个ILI9341的屏幕:

    1. 一个是3.2 inch 320x240 16bit Parallel接口。
    2. 一个是2.8 inch 320x240 SPI接口。
  • 由于16bit Parallel LCD会需要16个以上的GPIO大部分板子比较难支持到,这里尝试使用两个74HC595N串连(Daisy-chaining)起来,达到(Serial Input Parallel Output)效果来驱动屏幕。测试线路连接如下表所示。

RP2040 74HC565N(1) 74HC565N(2) 3.2 inch 16bit 2.8 inch SPI
GPIO0 DS SDI(MOSI)
GPIO1 SHCP SHCP SCK
GPIO2 RS DC
GPIO3 WR
GPIO4 RESET RESET
GPIO5 STCP STCP
VCC VCC VCC
VCC MR MR
GND GND GND GND GND
GND QE QE
Q7S DS
Q0 D00
Q1 D01
Q2 D02
Q3 D03
Q4 D04
Q5 D05
Q6 D06
Q7 D07
Q0 D08
Q1 D09
Q2 D10
Q3 D11
Q4 D12
Q5 D13
Q6 D14
Q7 D15
VCC VCC VCC VCC VCC
VCC BL(High Act)
VCC RD
GND CS CS
GND BL(Low Active)
  • 使用的初始寄存器的参数如下,发现初始化的命有顺序的限制,比如:0xf7不跟在0xe8后面,会出现屏幕无法显示的结果.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static const uint8_t st7789_init_seq[] = {
1, 20, 0x1, // Software reset
1, 10, 0x11, // Exit sleep mode
4, 0, 0xCF, 0x00, 0x83, 0x30,
4, 0, 0xE8, 0x85, 0x01, 0x79,
2, 2, 0xF7, 0x20,
3, 0, 0xEA, 0x00, 0x00,
2, 2, 0x3A, 0x55, // Set colour mode to 16 bit
2, 0, 0x36, 0x08, // Set MADCTL: row then column, refresh is bottom to top ????
5, 0, 0x2A, 0x00, 0x00, SCREEN_WIDTH >> 8, SCREEN_WIDTH & 0xff, // CASET: column addresses
5, 0, 0x2B, 0x00, 0x00, SCREEN_HEIGHT >> 8, SCREEN_HEIGHT & 0xff, // RASET: row addresses
3, 2, 0xB1, 0x0, 0x10, // Frame Rate control 100Hz
2, 2, 0xF2, 0x8,
2, 0, 0x26, 0x01,
16, 0, 0xE0, 0x1F, 0x36, 0x36, 0x3A, 0x0C, 0x05, 0x4F, 0X87, 0x3C, 0x08, 0x11, 0x35, 0x19, 0x13, 0x00,
16, 0, 0xE1, 0x00, 0x09, 0x09, 0x05, 0x13, 0x0A, 0x30, 0x78, 0x43, 0x07, 0x0E, 0x0A, 0x26, 0x2C, 0x1F,
1, 2, 0x13, // Normal display on, then 10 ms delay
1, 2, 0x29, // Main screen turn on, then wait 500 ms
0 // Terminate list
};
  • 最终使用GPIOs bit-banging shiftout(位移)的核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#define LSBFIRST 0
#define MSBFIRST 1

static inline void shiftout( uint16_t val,uint8_t bits) {
uint8_t bitOrder = MSBFIRST;
uint8_t i;
uint8_t max_len = bits - 1;
gpio_put(PIN_LATCH, 0);
for (i = 0; i < bits; i++) {
if (bitOrder == MSBFIRST)
{
gpio_put(PIN_DIN, (val & (1 << (max_len - i))) >> (max_len - i));
} else {
gpio_put(PIN_DIN, (val & (1 << i)) >> i);
}
gpio_put(PIN_CLK, 1);
sleep_us(1); // 如果只是驱动SPI的LCD,这里是不需要的,并且屏幕的刷新会流畅很多。
gpio_put(PIN_CLK, 0);
sleep_us(1); // 如果只是驱动SPI的LCD,这里是不需要的,并且屏幕的刷新会流畅很多。
}
gpio_put(PIN_WR, 0);
gpio_put(PIN_LATCH, 1);
gpio_put(PIN_WR, 1);
sleep_us(1); // 如果只是驱动SPI的LCD,这里是不需要的,并且屏幕的刷新会流畅很多。
}

static inline void lcd_send_cmd(const uint8_t cmd)
{
gpio_put(PIN_RS, 0);
shiftout(cmd, 8);
gpio_put(PIN_RS, 1);
}

static inline void lcd_send_data(const uint8_t data) {
gpio_put(PIN_RS, 1);
shiftout(data, 8);
}
  • 上面的代码可以同时驱动两块不一样接口的屏幕,但是速度非常的慢,类似一种灯箱广告加载的效果,主要是因为在shiftout里面有三处使用了sleep_us(1)导致的。但是这个地方不用sleep_us(1),3.2 inch 16bit就无法显示, 且使用__asm volatile("nop\n");都无法替代sleep_us(1).如果只是驱动SPILCD,去掉sleep_us(1),屏幕会流畅的刷新。

简单逻辑分析仪示例

  • Install Rust
1
2
3
4
~$ rustup target add thumbv6m-none-eabi
~$ rustup component add llvm-tools-preview
~$ cargo install cargo-binutils
~$ cargo install elf2uf2-rs
  • 连机编译与烧写运行
1
2
~$ git clone https://github.com/dotcypress/ula

  • Hold the BOOTSEL button while connecting your board to the computer, then run following command.
1
2
~$ cd ula
~$ cargo run --release

PulseView

  • Select Openbench Logic Sniffer & SUMP compatible protocol when connecting to μLA.

SigrokCli

  • Scan for devices
1
~$ sigrok-cli -d ols:conn=/dev/tty.usbmodem_ula_1 --scan
  • Sample two 10 MHz square waves with 90° phase shift
1
2
3
4
5
6
7
8
9
10
~$ sigrok-cli -d ols:conn=/dev/tty.usbmodem_ula_1
-O ascii:charset='_`\/'
--config samplerate=100m
--samples 70

libsigrok 0.5.2
Acquisition with 16/16 channels at 100 MHz
0:``\____/`````\___/`````\___/`````\___/`````\___/`````\___/`````\___/``
1:____/`````\____/````\____/````\____/````\____/````\____/````\____/````
2:______________________________________________________________________

LoRa通信

USB协议栈

USB结构简介

descriptor-table.svg

Descriptor Types

  • The most commonly used descriptors include:

    • Device Descriptor
    • Configuration Descriptor
    • Interface Descriptor
    • Endpoint Descriptor
    • String Descriptor
  • Every USB device must have one Device Descriptor and at least one each of the Configuration, Interface, and Endpoint Descriptors.

Device Descriptor

  • The Device Descriptor is the first descriptor read by the Host during enumeration. The purpose of the Device Descriptor is to let the Host know what specification of USB the device complies with and how many possible configurations are available on the device. Upon successful processing of the Device Descriptor, the Host will read all the Configuration Descriptors.

Configuration Descriptor

  • A device may have more than one configuration. Each device configuration is assigned a number. The Configuration Descriptor serves two purposes:

    Informs the Host as to how many interfaces (i.e., virtual devices) are in the configuration. While it is common for a configuration to offer only one interface, Devices that appear like two or more products have more than one interface.
    How much power the device will consume if this configuration is activated by the Host. If the device is capable of controlling its power consumption, it may offer more than one configuration. Each configuration will advertise how much power would be consumed if the configuration were to be activated.

Interface Descriptor

An Interface Descriptor describes the details of the function of the product. Key elements include the number of endpoints on the device and which USB device class is implemented by the endpoints. For example, if the device were a keyboard, the specified device class would be Human Interface Device (HID) and the number of endpoints would be two.

Endpoint Descriptor

  • Each endpoint on a device has its own descriptor. The descriptor provides the endpoint address (i.e., endpoint number), the size of the endpoint, and the data transfer type used to access the endpoint.
  • Endpoint 0 (EP0IN and EP0OUT) are reserved in every device for control purposes.
  • A USB device can have up to 32 endpoints (16 OUT and 16 IN). Since EP0IN and EP0OUT are set aside as control endpoints, the maximum number of endpoints available to transmit application data is 30.

String Descriptor

  • Strings Descriptors are optional human readable strings which the Host OS may display.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
~$ lsusb -v -s 001:005

Bus 001 Device 005: ID cafe:4020 TinyUSB TinyUSB Device
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0xcafe
idProduct 0x4020
bcdDevice 1.00
iManufacturer 1 TinyUSB
iProduct 2 TinyUSB Device
iSerial 3 E6609CB2D3995B33
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x00a7
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 14 Video
bFunctionSubClass 3 Video Interface Collection
bFunctionProtocol 0
iFunction 4 TinyUSB UVC
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 14 Video
bInterfaceSubClass 1 Video Control
bInterfaceProtocol 1
iInterface 4 TinyUSB UVC
VideoControl Interface Descriptor:
bLength 13
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdUVC 1.50
wTotalLength 0x0028
dwClockFrequency 27.000000MHz
bInCollection 1
baInterfaceNr( 0) 1
VideoControl Interface Descriptor:
bLength 18
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0201 Camera Sensor
bAssocTerminal 0
iTerminal 0
wObjectiveFocalLengthMin 0
wObjectiveFocalLengthMax 0
wOcularFocalLength 0
bControlSize 3
bmControls 0x00000000
VideoControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bSourceID 1
iTerminal 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 1
iInterface 4 TinyUSB UVC
VideoStreaming Interface Descriptor:
bLength 14
bDescriptorType 36
bDescriptorSubtype 1 (INPUT_HEADER)
bNumFormats 1
wTotalLength 0x0055
bEndpointAddress 0x81 EP 1 IN
bmInfo 0
bTerminalLink 2
bStillCaptureMethod 0
bTriggerSupport 0
bTriggerUsage 0
bControlSize 1
bmaControls( 0) 0
VideoStreaming Interface Descriptor:
bLength 27
bDescriptorType 36
bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
bFormatIndex 1
bNumFrameDescriptors 1
guidFormat {32595559-0000-0010-8000-00aa00389b71}
bBitsPerPixel 16
bDefaultFrameIndex 1
bAspectRatioX 0
bAspectRatioY 0
bmInterlaceFlags 0x00
Interlaced stream or variable: No
Fields per frame: 2 fields
Field 1 first: No
Field pattern: Field 1 only
bCopyProtect 0
VideoStreaming Interface Descriptor:
bLength 38
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 1
bmCapabilities 0x00
Still image unsupported
wWidth 160
wHeight 120
dwMinBitRate 307200
dwMaxBitRate 7680000
dwMaxVideoFrameBufferSize 307200
dwDefaultFrameInterval 400000
bFrameIntervalType 0
dwMinFrameInterval 400000
dwMaxFrameInterval 10000000
dwFrameIntervalStep 400000
VideoStreaming Interface Descriptor:
bLength 6
bDescriptorType 36
bDescriptorSubtype 13 (COLORFORMAT)
bColorPrimaries 1 (BT.709,sRGB)
bTransferCharacteristics 1 (BT.709)
bMatrixCoefficients 4 (SMPTE 170M (BT.601))
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Device Status: 0x0000
(Bus Powered)

USB Transfer Types

Desc Interrupt Transfers Isochronous Transfers Bulk Transfers
Benefits High-reliability data transfers with a fixed response time High bandwidth High reliability with the potential for high bandwidth
Drawback Bandwidth may be limited (64 KBytes for Full-Speed USB) No CRC hardware. If a CRC is needed it must be done in software. Long packets can limit the number of devices being enumerated. Bandwidth may vary depending upon the number of interrupt endpoints enumerated and the activity of enumerated Isochronous endpoints.
Typical Use Mice, Keyboards, and Medical Devices Audio/Video streaming, serial port emulation Mass Storage and Printers
Notes Up to 90 percent of the frame can be allocated for Interrupt endpoints.The maximum length of the transfer depends upon the frame size used. Up to 90 percent of the frame can be allocated for interrupt endpoints. When not in use the bandwidth used will be released. The maximum length of the transfer depends upon the frame size used. Will take advantage of unused Isochronous bandwidth.The maximum length of the transfer depends upon the frame size used.

Linux USB手抓包分析

1
2
3
4
5
~$ lsmod | grep "usbmon"
usbmon 40960 0
usbcore 389120 12 ftdi_sio,usbserial,xhci_hcd,usbmon,usbhid,cdc_acm,usb_storage,uvcvideo,btusb,xhci_pci,uas,hid_logitech_hidpp
usb_common 16384 4 xhci_hcd,usbmon,usbcore,uvcvideo

  • 这里测试需要监听的要目标设备,是TinyUSB的设备,在Bus 3, Device 90,
1
2
~$  lsusb  | grep "TinyUSB"
Bus 003 Device 090: ID cafe:4020 TinyUSB TinyUSB Device
  • 打开wireshark, 选择usbmon3开始抓包。如下图所示,这里抓到的是错误码的UVC的包。

usbmon-capture-by-wireshark.png

  • 下面示例抓取一个正常的UVC的协议包。在Bus 3, Device 91,
1
2
~$ lsusb | grep "EM-Camera"
Bus 003 Device 091: ID 1e4e:0110 Cubeternet USB 2.0 EM-Camera2 5M

usbmon-capture-by-wireshark-uvc_ok.png

UVC相关

MicroPython

下载安装MicroPython的固件

  • Download the correct MicroPython UF2 file for your board:

  • Then go ahead and:

    1. Push and hold the BOOTSEL button and plug your Pico into the USB port of your Raspberry Pi or other computer. Release the BOOTSEL button after your Pico is connected.
    2. It will mount as a Mass Storage Device called RPI-RP2.
    3. Drag and drop the MicroPython UF2 file onto the RPI-RP2 volume. Your Pico will reboot. You are now running MicroPython.
    4. You can access the REPL via USB Serial.

通过USB访问UART串口

  • 可以使用minicom,也可以使用mpremote这里推荐使用后者。
1
2
3
4
5
6
~$ pip install mpremote

~$ mpremote connect list
/dev/ttyACM0 e661410403724d2a 2e8a:0005 MicroPython Board in FS mode
/dev/ttyS0 None 0000:0000 None None

测试ULN2003步进电机驱动

RP2040 ULN2003
GPIO2 IN1
GPIO3 IN2
GPIO4 IN3
GPIO5 IN4
GND GND
VUSB +5V
  • 使用minicom -o -b 115200 -D /dev/ttyACM0连接到RP2040REPL命令行终端,输入以下的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import time
from machine import Pin

IN1 = Pin(2,Pin.OUT)
IN2 = Pin(3,Pin.OUT)
IN3 = Pin(4,Pin.OUT)
IN4 = Pin(5,Pin.OUT)

pins = [IN1, IN2, IN3, IN4]
steps = [
[IN1],
[IN1, IN2],
[IN2],
[IN2, IN3],
[IN3],
[IN3, IN4],
[IN4],
[IN4, IN1],
]
current_step = 0

def set_pins_low(pins):
[pin.low() for pin in pins]


def set_pins_high(pins):
[pin.high() for pin in pins]
while True:
high_pins = steps[current_step]
set_pins_low(pins)
set_pins_high(high_pins)
current_step += 1
if current_step == len(steps):
current_step = 0
time.sleep(0.001)
  • 也可以把上面的代码保存成文件如:test_stepper_motor.py,使用mpremote运行:
1
~$ mpremote run test_stepper_motor.py

测试Pico-W WIFI

  • 先要确保存Pico-W安装正确的固件Raspberry Pi Pico W,才能进行下面的测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
~$ cat test_wifi.py
import time
import network

ssid = 'your ssid'
password = 'wifi pwd'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
time.sleep(1)

# Handle connection error
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
print( 'ip = ' + status[0] )

print("ifconfig ----------------------------->")
print(wlan.ifconfig())

  • 使用mpremote运行
1
2
3
4
5
6
7
8
9
~$ mpremote run test_wifi.py
waiting for connection...
waiting for connection...
waiting for connection...
connected
ip = 192.168.4.50
ifconfig ----------------------------->
('192.168.4.50', '255.255.255.0', '192.168.4.1', '192.168.4.1')

测试ILI9341+XPT2046

1
~$ git clone https://github.com/rdagger/micropython-ili9341
  • 上传依赖文件到rp2040,设置好正确接线。
1
2
3
4
5
6
~$ cd micropython-ili9341
~ micropython-ili9341$ mpremote fs cp ili9341.py :ili9341.py

~$ cd micropython-ili9341
~ micropython-ili9341$ mpremote fs cp xpt2046.py :xpt2046.py

  • 创建测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
~ micropython-ili9341$ cat demo_touch.py
"""ILI9341 demo (simple touch demo)."""
from ili9341 import Display, color565
from xpt2046 import Touch
from machine import idle, Pin, SPI # type: ignore


class Demo(object):
"""Touchscreen simple demo."""
CYAN = color565(0, 255, 255)
PURPLE = color565(255, 0, 255)
WHITE = color565(255, 255, 255)

def __init__(self, display, spi2):
"""Initialize box.

Args:
display (ILI9341): display object
spi2 (SPI): SPI bus
"""
self.display = display
self.touch = Touch(spi2, cs=Pin(13), int_pin=Pin(9),
int_handler=self.touchscreen_press)
# Display initial message
self.display.draw_text8x8(self.display.width // 2 - 32,
self.display.height - 9,
"TOUCH ME",
self.WHITE,
background=self.PURPLE)

# A small 5x5 sprite for the dot
self.dot = bytearray(b'\x00\x00\x07\xE0\xF8\x00\x07\xE0\x00\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\xF8\x00\xF8\x00\x07\xE0\xF8\x00\xF8\x00\xF8\x00\x07\xE0\x00\x00\x07\xE0\xF8\x00\x07\xE0\x00\x00')

def touchscreen_press(self, x, y):
"""Process touchscreen press events."""
# Y needs to be flipped
y = (self.display.height - 1) - y
# Display coordinates
self.display.draw_text8x8(self.display.width // 2 - 32,
self.display.height - 9,
"{0:03d}, {1:03d}".format(x, y),
self.CYAN)
# Draw dot
self.display.draw_sprite(self.dot, x - 2, y - 2, 5, 5)


def test():
"""Test code."""
spi1 = SPI(0, baudrate=40000000, sck=Pin(2), mosi=Pin(3))
display = Display(spi1, dc=Pin(0), cs=Pin(5), rst=Pin(1))
spi2 = SPI(1, baudrate=1000000, sck=Pin(14), mosi=Pin(15), miso=Pin(12))

Demo(display, spi2)

try:
while True:
idle()

except KeyboardInterrupt:
print("\nCtrl-C pressed. Cleaning up and exiting...")
finally:
display.cleanup()


test()


~micropython-ili9341$ mpremote run demo_touch.py

测试使用lv_micropython

1
2
3
4
5
6
~$ git clone https://github.com/lvgl/lv_micropython.git
~$ cd lv_micropython
~$ git submodule update --init --recursive lib/lv_bindings
~$ make -C ports/rp2 BOARD=PICO submodules
~$ make -j -C mpy-cross
~$ make -j -C ports/rp2 BOARD=PICO USER_C_MODULES=../../lib/lv_bindings/bindings.cmake
  • Write firmware to device
1
~ lv_micropython$ cp ports/rp2/build-PICO/firmware.uf2 /media/michael/RPI-RP2/

CC1101

联系作者