diff --git a/CMakelist.txt b/CMakelist.txt new file mode 100644 index 0000000..f800181 --- /dev/null +++ b/CMakelist.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.13) +include(pico_sdk_import.cmake) +project(test_project C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +pico_sdk_init() + +if (TARGET tinyusb_device) + add_executable(hello_pio_usb) + +pico_generate_pio_header(hello_pio_usb ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/generated) + + + #pull in common dependencies + target_sources(hello_pio_usb PRIVATE ws2812.c ws2812.h hello_usb.c ws2812.pio) + # pull in common dependencies + target_link_libraries(hello_pio_usb pico_stdlib hardware_pio ) + + # enable usb output, disable uart output + pico_enable_stdio_usb(hello_pio_usb 1) + pico_enable_stdio_uart(hello_pio_usb 0) + + # create map/bin/hex/uf2 file etc. + pico_add_extra_outputs(hello_pio_usb) + + # add url via pico_set_program_url +elseif(PICO_ON_DEVICE) + message(WARNING "not building hello_usb because TinyUSB submodule is not initialized in the SDK") +endif() diff --git a/README.md b/README.md index a8be84b..d40ddaf 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,98 @@ University of Pennsylvania, ESE 5190: Intro to Embedded Systems, Lab 2A - (TODO) YOUR NAME HERE - (TODO) LinkedIn, personal website, twitter, etc. - Tested on: (TODO) MacBook Pro (14-inch, 2021), macOS Monterey 12.5.1 + Zihan Zhang + zihanzh@seas.upenn.edu + Tested on: Ubantu + +#Part 3.2 + + Why is bit-banging impractical on your laptop, despite it having a much faster processor than the RP2040? + If the processor is interrupted to attend to one of the hard peripherals it is also responsible for, it can be fatal to the timing of any bit-banged protocol. And + the ratio between the processor speed and protocol speed is big, so the processor will spend uselessly idling in between GPIO accesses. + + What are some cases where directly using the GPIO might be a better choice than using the PIO hardware? + The main case where software GPIO access is the best choice is LEDs and push buttons. + + How do you get data into a PIO state machine? + Use pio_sm_put_blocking() function to push data directly into the state machine’s TXFIFO. + + How do you get data out of a PIO state machine? + Use pull instruction first to take one data item from the transmit FIFO buffer, and places it in the output shift register (OSR). Then use out instruction to + write that data to some pins. + + How do you program a PIO state machine? + System software loads data into the PIO's instruction memory and then set the i/o mapping. + + In the example, which low-level C SDK function is directly responsible for telling the PIO to set the LED to a new color? How is this function accessed from the + main “application” code? + pio_sm_put_blocking pio_sm_put_blocking() is called with the parameters from the put_pixel(). + + What role does the pioasm “assembler” play in the example, and how does this interact with CMake? + Our program written in C language can be built to assembler with GCC. We can use CMake to generate uf2 file which can be recognized by the board. + +#Part3.3 + + I put this document in part3.3.pdf
+ + image
+ image
+ image
+ image
+ image
+ image
+ image
+ +#Part3.4 + + I put this document in part3.4.xlsx
+ +#Part3.5 + + I put this document in part3.5.pdf
+ + ![image](https://user-images.githubusercontent.com/114272466/196425034-956fe653-a823-48e1-892a-41bf81dc413c.png)#Part3.5
+ +#Part3.6 + + I put this document in part3.6.xlsx
+ +#Part3.7 + + I put this document in part3.7.pdf
+ ![image](https://user-images.githubusercontent.com/114272466/196425697-8027d36a-c7af-4fa4-a831-07cd2b553ab0.png)
+ +#Part4 Hello_world
+ ![image](https://user-images.githubusercontent.com/114272466/196427660-26ddf1e4-1cd5-432a-9c07-fa4104f092fe.png)
+ + For this project, I add the gpio in hello_usb.c and add ws2812.h. At the mean time, I add the fuction in ws2812.c. + Additionally, I mix two CMakelists.txt into one doucment. Finally, I made it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + -(TODO: Your README) -Include lab questions, screenshots, analysis, etc. (Remember, this is public, so don't put anything here you don't want to share with the world.) diff --git a/hello_usb.c b/hello_usb.c new file mode 100644 index 0000000..67e8cdd --- /dev/null +++ b/hello_usb.c @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "ws2812.h" + + +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" +#include "ws2812.pio.h" + +#define IS_RGBW true +#define NUM_PIXELS 150 + +#ifdef PICO_DEFAULT_WS2812_PIN +#define WS2812_PIN PICO_DEFAULT_WS2812_PIN +#else +// default to pin 2 if the board doesn't have a default WS2812 pin defined +#define WS2812_PIN 12 +#endif +int main() { + stdio_init_all(); + gpio_init(11); + gpio_set_dir(11, GPIO_OUT); + gpio_put(11, 1); + PIO pio = pio0; + int sm = 0; + uint offset = pio_add_program(pio, &ws2812_program); + ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW); + while (true) { + printf("Hello, world!\n"); + sleep_ms(500); + set_neopixel_color(0x00337788); + sleep_ms(500); + printf("see you!\n"); + set_neopixel_color(0); + sleep_ms(500); + + } + return 0; +} diff --git a/part3.3.pdf b/part3.3.pdf new file mode 100644 index 0000000..67b0f63 Binary files /dev/null and b/part3.3.pdf differ diff --git a/part3.4.xlsx b/part3.4.xlsx new file mode 100644 index 0000000..88200b5 Binary files /dev/null and b/part3.4.xlsx differ diff --git a/part3.5.pdf b/part3.5.pdf new file mode 100644 index 0000000..eaf6b57 Binary files /dev/null and b/part3.5.pdf differ diff --git a/part3.7.pdf b/part3.7.pdf new file mode 100644 index 0000000..c9a96f6 Binary files /dev/null and b/part3.7.pdf differ diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 0000000..65f8a6f --- /dev/null +++ b/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/port3.6 .xlsx b/port3.6 .xlsx new file mode 100644 index 0000000..545cea2 Binary files /dev/null and b/port3.6 .xlsx differ diff --git a/ws2812.c b/ws2812.c new file mode 100644 index 0000000..c8a9254 --- /dev/null +++ b/ws2812.c @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" +#include "ws2812.pio.h" + +#define IS_RGBW true +#define NUM_PIXELS 150 + +#ifdef PICO_DEFAULT_WS2812_PIN +#define WS2812_PIN PICO_DEFAULT_WS2812_PIN +#else +// default to pin 2 if the board doesn't have a default WS2812 pin defined +#define WS2812_PIN 12 +#endif + +static inline void put_pixel(uint32_t pixel_grb) { + pio_sm_put_blocking(pio0, 0, pixel_grb << 8u); +} + +static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) { + return + ((uint32_t) (r) << 8) | + ((uint32_t) (g) << 16) | + (uint32_t) (b); +} + +void pattern_snakes(uint len, uint t) { + for (uint i = 0; i < len; ++i) { + uint x = (i + (t >> 1)) % 64; + if (x < 10) + put_pixel(urgb_u32(0xff, 0, 0)); + else if (x >= 15 && x < 25) + put_pixel(urgb_u32(0, 0xff, 0)); + else if (x >= 30 && x < 40) + put_pixel(urgb_u32(0, 0, 0xff)); + else + put_pixel(0); + } +} + +void pattern_random(uint len, uint t) { + if (t % 8) + return; + for (int i = 0; i < len; ++i) + put_pixel(rand()); +} + +void pattern_sparkle(uint len, uint t) { + if (t % 8) + return; + for (int i = 0; i < len; ++i) + put_pixel(rand() % 16 ? 0 : 0xffffffff); +} + +void pattern_greys(uint len, uint t) { + int max = 100; // let's not draw too much current! + t %= max; + for (int i = 0; i < len; ++i) { + put_pixel(t * 0x10101); + if (++t >= max) t = 0; + } +} + +void set_neopixel_color(uint32_t color){ + + uint8_t r=color>>16; + uint8_t g=color>>8; + uint8_t b=color; + uint32_t result=urgb_u32(r,g,b); + put_pixel(result); + +} + +typedef void (*pattern)(uint len, uint t); +const struct { + pattern pat; + const char *name; +} pattern_table[] = { + {pattern_snakes, "Snakes!"}, + {pattern_random, "Random data"}, + {pattern_sparkle, "Sparkles"}, + {pattern_greys, "Greys"}, +}; + +//int main() { + //set_sys_clock_48(); +// stdio_init_all(); +// printf("WS2812 Smoke Test, using pin %d", WS2812_PIN); +// gpio_init(11); +// gpio_set_dir(11,GPIO_OUT); +// gpio_put(11,1); +// // todo get free sm +// PIO pio = pio0; +// int sm = 0; +// uint offset = pio_add_program(pio, &ws2812_program); +// +// ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW); +// +// int t = 0; +// while (1) { +// int pat = rand() % count_of(pattern_table); +// int dir = (rand() >> 30) & 1 ? 1 : -1; +// puts(pattern_table[pat].name); +// puts(dir == 1 ? "(forward)" : "(backward)"); +// for (int i = 0; i < 1000; ++i) { +// pattern_table[pat].pat(NUM_PIXELS, t); +// sleep_ms(10); +// t += dir; +// } +// } +//} diff --git a/ws2812.h b/ws2812.h new file mode 100644 index 0000000..43b528a --- /dev/null +++ b/ws2812.h @@ -0,0 +1,4 @@ +#ifndef _WS2812_H +#define _WS2812_H +void set_neopixel_color(uint32_t color); +#endif diff --git a/ws2812.pio b/ws2812.pio new file mode 100644 index 0000000..3c31fd6 --- /dev/null +++ b/ws2812.pio @@ -0,0 +1,85 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program ws2812 +.side_set 1 + +.define public T1 2 +.define public T2 5 +.define public T3 3 + +.lang_opt python sideset_init = pico.PIO.OUT_HIGH +.lang_opt python out_init = pico.PIO.OUT_HIGH +.lang_opt python out_shiftdir = 1 + +.wrap_target +bitloop: + out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls + jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse +do_one: + jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse +do_zero: + nop side 0 [T2 - 1] ; Or drive low, for a short pulse +.wrap + +% c-sdk { +#include "hardware/clocks.h" + +static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) { + + pio_gpio_init(pio, pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + + pio_sm_config c = ws2812_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, pin); + sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + + int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3; + float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit); + sm_config_set_clkdiv(&c, div); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} +%} + +.program ws2812_parallel + +.define public T1 2 +.define public T2 5 +.define public T3 3 + +.wrap_target + out x, 32 + mov pins, !null [T1-1] + mov pins, x [T2-1] + mov pins, null [T3-2] +.wrap + +% c-sdk { +#include "hardware/clocks.h" + +static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset, uint pin_base, uint pin_count, float freq) { + for(uint i=pin_base; i