mirror of
https://github.com/FizzyApple12/Waccon.git
synced 2026-09-22 23:08:05 +03:00
Initial commit with V1 hardware
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
WaccaProtocolTranslator/build/
|
||||
|
||||
WaccaProtocolTranslator/.vscode/
|
||||
|
||||
WaccaTouchPanel/build/
|
||||
|
||||
WaccaTouchPanel/.vscode/
|
||||
|
||||
/**/OldVersions/
|
||||
@@ -0,0 +1,3 @@
|
||||
# Wacca Controller
|
||||
|
||||
This repo is right now still a work in progress, nothing has been finalized and things will probably be broken, stay tuned as things are finalized though!
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(PICO_SDK_FETCH_FROM_GIT on)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(WaccaTouchPanel)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(wacca_protocol_translator
|
||||
main.c
|
||||
waccaserial.h
|
||||
waccaserial.c
|
||||
queue.h
|
||||
queue.c
|
||||
)
|
||||
|
||||
# Add pico_stdlib library which aggregates commonly used features
|
||||
target_link_libraries(wacca_protocol_translator
|
||||
pico_stdlib
|
||||
hardware_i2c
|
||||
pico_multicore
|
||||
pico_stdio
|
||||
pico_stdio_usb
|
||||
)
|
||||
|
||||
# create map/bin/hex/uf2 file in addition to ELF.
|
||||
pico_add_extra_outputs(wacca_protocol_translator)
|
||||
|
||||
pico_enable_stdio_usb(wacca_protocol_translator 1)
|
||||
pico_enable_stdio_uart(wacca_protocol_translator 0)
|
||||
@@ -0,0 +1,5 @@
|
||||
if not exist "build" mkdir build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" ..
|
||||
make wacca_protocol_translator
|
||||
cd ..
|
||||
@@ -0,0 +1,5 @@
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" ..
|
||||
make wacca_protocol_translator
|
||||
cd ..
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <stdbool.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include "waccaserial.h"
|
||||
|
||||
#define TOUCH_I2C_PORT i2c0
|
||||
#define TOUCH_I2C_SDA 6
|
||||
#define TOUCH_I2C_SCL 7
|
||||
#define TOUCH_PANEL_0_ADDR 0x11
|
||||
#define TOUCH_PANEL_1_ADDR 0x11 //0x12
|
||||
#define TOUCH_PANEL_2_ADDR 0x11 //0x13
|
||||
#define TOUCH_PANEL_3_ADDR 0x11 //0x14
|
||||
#define TOUCH_PANEL_4_ADDR 0x11 //0x15
|
||||
#define TOUCH_PANEL_5_ADDR 0x11 //0x16
|
||||
#define TOUCH_I2C_FREQ 100000
|
||||
|
||||
uint32_t touchPanel0Data = 0;
|
||||
uint32_t touchPanel1Data = 0;
|
||||
uint32_t touchPanel2Data = 0;
|
||||
uint32_t touchPanel3Data = 0;
|
||||
uint32_t touchPanel4Data = 0;
|
||||
uint32_t touchPanel5Data = 0;
|
||||
|
||||
|
||||
uint32_t getTouchPacket(i2c_inst_t *port, uint8_t addr) {
|
||||
int bytesRead = 0;
|
||||
uint8_t data[4];
|
||||
uint8_t dummyRegister = 0x69;
|
||||
|
||||
i2c_write_blocking(port, addr, &dummyRegister, 1, true); // it's okay to use blocking methods, the main protocol translation is running on a seperate cpu core
|
||||
bytesRead = i2c_read_blocking(port, addr, data, 4, false);
|
||||
|
||||
if (bytesRead != 4) return 0;
|
||||
|
||||
return (uint32_t) (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
|
||||
}
|
||||
|
||||
#define PingWaccaPanel(ADDR, final) do { final = getTouchPacket(TOUCH_I2C_PORT, ADDR); } while (final == 0)
|
||||
|
||||
void setupTouchPanels() {
|
||||
i2c_init(TOUCH_I2C_PORT, TOUCH_I2C_FREQ);
|
||||
|
||||
gpio_set_function(TOUCH_I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(TOUCH_I2C_SCL, GPIO_FUNC_I2C);
|
||||
|
||||
gpio_pull_up(TOUCH_I2C_SDA);
|
||||
gpio_pull_up(TOUCH_I2C_SCL);
|
||||
|
||||
PingWaccaPanel(TOUCH_PANEL_0_ADDR, touchPanel0Data);
|
||||
PingWaccaPanel(TOUCH_PANEL_1_ADDR, touchPanel1Data);
|
||||
PingWaccaPanel(TOUCH_PANEL_2_ADDR, touchPanel2Data);
|
||||
PingWaccaPanel(TOUCH_PANEL_3_ADDR, touchPanel3Data);
|
||||
PingWaccaPanel(TOUCH_PANEL_4_ADDR, touchPanel4Data);
|
||||
PingWaccaPanel(TOUCH_PANEL_5_ADDR, touchPanel5Data);
|
||||
|
||||
ws_setTouchData(touchPanel0Data, touchPanel1Data, touchPanel2Data, touchPanel3Data, touchPanel4Data, touchPanel5Data);
|
||||
}
|
||||
|
||||
int main() {
|
||||
setupTouchPanels();
|
||||
|
||||
ws_start();
|
||||
|
||||
while(1) { // note: getting a touch packet might take a bit, use this rolling update to speed up input throughput to the game
|
||||
touchPanel0Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_0_ADDR);
|
||||
ws_setTouch0Data(touchPanel0Data);
|
||||
|
||||
touchPanel1Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_1_ADDR);
|
||||
ws_setTouch1Data(touchPanel1Data);
|
||||
|
||||
touchPanel2Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_2_ADDR);
|
||||
ws_setTouch2Data(touchPanel2Data);
|
||||
|
||||
touchPanel3Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_3_ADDR);
|
||||
ws_setTouch3Data(touchPanel3Data);
|
||||
|
||||
touchPanel4Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_4_ADDR);
|
||||
ws_setTouch4Data(touchPanel4Data);
|
||||
|
||||
touchPanel5Data = getTouchPacket(TOUCH_I2C_PORT, TOUCH_PANEL_5_ADDR);
|
||||
ws_setTouch5Data(touchPanel5Data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/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})
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "queue.h"
|
||||
|
||||
void enqueue(node_t **head, int val) {
|
||||
node_t *new_node = malloc(sizeof(node_t));
|
||||
if (!new_node) return;
|
||||
|
||||
new_node->val = val;
|
||||
new_node->next = *head;
|
||||
|
||||
*head = new_node;
|
||||
}
|
||||
|
||||
int dequeue(node_t **head) {
|
||||
node_t *current, *prev = NULL;
|
||||
int retval = -1;
|
||||
|
||||
if (*head == NULL) return -1;
|
||||
|
||||
current = *head;
|
||||
while (current->next != NULL) {
|
||||
prev = current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
retval = current->val;
|
||||
free(current);
|
||||
|
||||
if (prev)
|
||||
prev->next = NULL;
|
||||
else
|
||||
*head = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool isEmpty(node_t **head) {
|
||||
return *head == NULL;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _QUEUE_
|
||||
#define _QUEUE_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct node {
|
||||
int val;
|
||||
struct node *next;
|
||||
} node_t;
|
||||
|
||||
void enqueue(node_t **head, int val);
|
||||
|
||||
int dequeue(node_t **head);
|
||||
|
||||
bool isEmpty(node_t **head);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,265 @@
|
||||
#include "waccaserial.h"
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
#include "pico/stdio_usb.h"
|
||||
|
||||
// Massive thank you to the contributors for the WACVR project <3
|
||||
|
||||
uint8_t TouchPack[36] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
bool StartUp = false;
|
||||
uint8_t inByte = 0;
|
||||
|
||||
node_t *touchQueueHead = NULL;
|
||||
|
||||
uint32_t elapsedTime = 0;
|
||||
uint32_t previousTime = 0;
|
||||
|
||||
bool runningMulticore = false;
|
||||
|
||||
void ws_start() {
|
||||
stdio_usb_init();
|
||||
|
||||
previousTime = to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
void ws_touchThreadLoop() {
|
||||
while (true) {
|
||||
uint32_t currentTime = to_ms_since_boot(get_absolute_time());
|
||||
elapsedTime += currentTime - previousTime;
|
||||
previousTime = currentTime;
|
||||
|
||||
if (elapsedTime >= 1000) {
|
||||
elapsedTime -= 1000;
|
||||
enqueue(&touchQueueHead, 1);
|
||||
}
|
||||
|
||||
if (!isEmpty(&touchQueueHead)) {
|
||||
dequeue(&touchQueueHead);
|
||||
ws_sendTouchState();
|
||||
}
|
||||
|
||||
if (stdio_usb_connected()) ws_readHead();
|
||||
}
|
||||
}
|
||||
|
||||
void ws_sendTouchState() {
|
||||
if (StartUp) ws_sendTouch();
|
||||
}
|
||||
|
||||
void ws_readHead() {
|
||||
uint8_t inByte = getchar_timeout_us(0);
|
||||
|
||||
if (inByte != 0) {
|
||||
uint8_t data = 0;
|
||||
uint8_t importantData = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
data = getchar_timeout_us(0);
|
||||
if (i == 2) importantData = data;
|
||||
i++;
|
||||
} while (data != 0);
|
||||
|
||||
ws_sendResp(importantData);
|
||||
}
|
||||
}
|
||||
|
||||
void ws_sendResp(char importantNextReadData) {
|
||||
switch (inByte) {
|
||||
case CMD_GET_SYNC_BOARD_VER:
|
||||
StartUp = false;
|
||||
|
||||
putchar_raw(inByte);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
putchar_raw(SYNC_BOARD_VER[i]);
|
||||
}
|
||||
|
||||
putchar_raw(44);
|
||||
break;
|
||||
case CMD_NEXT_READ:
|
||||
StartUp = false;
|
||||
switch (importantNextReadData) {
|
||||
case 0x30:
|
||||
for (int i = 0; i < 80; i++) {
|
||||
putchar_raw(read1[i]);
|
||||
}
|
||||
|
||||
putchar_raw(bh_calcChecksum((uint8_t *) read1, 80));
|
||||
break;
|
||||
case 0x31:
|
||||
for (int i = 0; i < 80; i++) {
|
||||
putchar_raw(read2[i]);
|
||||
}
|
||||
|
||||
putchar_raw(bh_calcChecksum((uint8_t *) read2, 80));
|
||||
break;
|
||||
case 0x33:
|
||||
for (int i = 0; i < 80; i++) {
|
||||
putchar_raw(read3[i]);
|
||||
}
|
||||
|
||||
putchar_raw(bh_calcChecksum((uint8_t *) read3, 80));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CMD_GET_UNIT_BOARD_VER:
|
||||
putchar_raw(inByte);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
putchar_raw(SYNC_BOARD_VER[i]);
|
||||
}
|
||||
|
||||
#ifdef RIGHT
|
||||
putchar_raw('R');
|
||||
#endif
|
||||
#ifndef RIGHT
|
||||
putchar_raw('L');
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
putchar_raw(UNIT_BOARD_VER[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RIGHT
|
||||
putchar_raw(118);
|
||||
#endif
|
||||
#ifndef RIGHT
|
||||
putchar_raw(104);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case CMD_MYSTERY1:
|
||||
StartUp = false;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
putchar_raw(SettingData_162[i]);
|
||||
}
|
||||
break;
|
||||
case CMD_MYSTERY2:
|
||||
StartUp = false;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
putchar_raw(SettingData_148[i]);
|
||||
}
|
||||
break;
|
||||
case CMD_START_AUTO_SCAN:
|
||||
for (int i = 0; i < 7; i++) {
|
||||
putchar_raw(SettingData_201[i]);
|
||||
}
|
||||
|
||||
StartUp = true;
|
||||
|
||||
if (!runningMulticore) {
|
||||
multicore_launch_core1(ws_touchThreadLoop);
|
||||
runningMulticore = true;
|
||||
}
|
||||
break;
|
||||
case CMD_BEGIN_WRITE:
|
||||
break;
|
||||
case CMD_NEXT_WRITE:
|
||||
break;
|
||||
case 154:
|
||||
StartUp = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ws_getTouchPack() {
|
||||
TouchPack[0] = 129;
|
||||
TouchPack[34] = TouchPack[34] + 1;
|
||||
TouchPack[35] = 128;
|
||||
TouchPack[35] = bh_calcChecksum(TouchPack, 36);
|
||||
if (TouchPack[34] > 127) TouchPack[34] = 0;
|
||||
}
|
||||
|
||||
void ws_sendTouch() {
|
||||
if (StartUp) {
|
||||
ws_getTouchPack();
|
||||
|
||||
for (int i = 0; i < 36; i++) {
|
||||
putchar_raw(TouchPack[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// since i want the wacca panels to be as simple as possible, i need to reverse the input order on the right side to fit with how the game reads data
|
||||
#ifdef RIGHT
|
||||
uint8_t reverseAndShift(uint8_t b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b >> 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
// if im not on on the right then no flip needs to happen so we can just return the byte as normal
|
||||
#ifndef RIGHT
|
||||
uint8_t reverseAndShift(uint8_t b) {
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define getRow1(segment) reverseAndShift((uint8_t) ((segment & 0b00000000000000000000000000011111)))
|
||||
#define getRow2(segment) reverseAndShift((uint8_t) ((segment & 0b00000000000000000000001111100000) >> 5))
|
||||
#define getRow3(segment) reverseAndShift((uint8_t) ((segment & 0b00000000000000000111110000000000) >> 10))
|
||||
#define getRow4(segment) reverseAndShift((uint8_t) ((segment & 0b00000000000011111000000000000000) >> 15))
|
||||
|
||||
void ws_setTouch0Data(uint32_t touchSegment0) {
|
||||
TouchPack[6] = getRow1(touchSegment0);
|
||||
TouchPack[12] = getRow2(touchSegment0);
|
||||
TouchPack[18] = getRow3(touchSegment0);
|
||||
TouchPack[24] = getRow4(touchSegment0);
|
||||
}
|
||||
|
||||
void ws_setTouch1Data(uint32_t touchSegment1) {
|
||||
TouchPack[5] = getRow1(touchSegment1);
|
||||
TouchPack[11] = getRow2(touchSegment1);
|
||||
TouchPack[17] = getRow3(touchSegment1);
|
||||
TouchPack[23] = getRow4(touchSegment1);
|
||||
}
|
||||
|
||||
void ws_setTouch2Data(uint32_t touchSegment2) {
|
||||
TouchPack[4] = getRow1(touchSegment2);
|
||||
TouchPack[10] = getRow2(touchSegment2);
|
||||
TouchPack[16] = getRow3(touchSegment2);
|
||||
TouchPack[22] = getRow4(touchSegment2);
|
||||
}
|
||||
|
||||
void ws_setTouch3Data(uint32_t touchSegment3) {
|
||||
TouchPack[3] = getRow1(touchSegment3);
|
||||
TouchPack[9] = getRow2(touchSegment3);
|
||||
TouchPack[15] = getRow3(touchSegment3);
|
||||
TouchPack[21] = getRow4(touchSegment3);
|
||||
}
|
||||
|
||||
void ws_setTouch4Data(uint32_t touchSegment4) {
|
||||
TouchPack[2] = getRow1(touchSegment4);
|
||||
TouchPack[8] = getRow2(touchSegment4);
|
||||
TouchPack[14] = getRow3(touchSegment4);
|
||||
TouchPack[20] = getRow4(touchSegment4);
|
||||
}
|
||||
|
||||
void ws_setTouch5Data(uint32_t touchSegment5) {
|
||||
TouchPack[1] = getRow1(touchSegment5);
|
||||
TouchPack[7] = getRow2(touchSegment5);
|
||||
TouchPack[13] = getRow3(touchSegment5);
|
||||
TouchPack[19] = getRow4(touchSegment5);
|
||||
}
|
||||
|
||||
void ws_setTouchData(uint32_t touchSegment0, uint32_t touchSegment1, uint32_t touchSegment2, uint32_t touchSegment3, uint32_t touchSegment4, uint32_t touchSegment5) {
|
||||
ws_setTouch0Data(touchSegment0);
|
||||
ws_setTouch1Data(touchSegment1);
|
||||
ws_setTouch2Data(touchSegment2);
|
||||
ws_setTouch3Data(touchSegment3);
|
||||
ws_setTouch4Data(touchSegment4);
|
||||
ws_setTouch5Data(touchSegment5);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef _WACCA_SERIAL_
|
||||
#define _WACCA_SERIAL_
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
#include "pico/stdio_usb.h"
|
||||
|
||||
// Massive thank you to the contributors for the WACVR project <3
|
||||
|
||||
//#define RIGHT //uncomment to enable righty flip on interface and sync board data swap
|
||||
|
||||
#define CMD_GET_SYNC_BOARD_VER 0xa0
|
||||
#define CMD_NEXT_READ 0x72
|
||||
#define CMD_GET_UNIT_BOARD_VER 0xa8
|
||||
#define CMD_MYSTERY1 0xa2
|
||||
#define CMD_MYSTERY2 0x94
|
||||
#define CMD_START_AUTO_SCAN 0xc9
|
||||
#define CMD_BEGIN_WRITE 0x77
|
||||
#define CMD_NEXT_WRITE 0x20
|
||||
|
||||
static const uint8_t SYNC_BOARD_VER[6] = "190523";
|
||||
static const uint8_t UNIT_BOARD_VER[6] = "190514";
|
||||
static const uint8_t read1[80] = " 0 0 1 2 3 4 5 15 15 15 15 15 15 11 11 11";
|
||||
static const uint8_t read2[80] = " 11 11 11 128 103 103 115 138 127 103 105 111 126 113 95 100";
|
||||
static const uint8_t read3[80] = " 101 115 98 86 76 67 68 48 117 0 82 154 0 6 35 4";
|
||||
|
||||
static const uint8_t SettingData_160[8] = { 160, 49, 57, 48, 53, 50, 51, 44 };
|
||||
static const uint8_t SettingData_162[7] = { 162, 63, 29, 0, 0, 0, 0 };
|
||||
static const uint8_t SettingData_148[7] = { 148, 0, 20, 0, 0, 0, 0 };
|
||||
static const uint8_t SettingData_201[7] = { 201, 0, 73, 0, 0, 0, 0 };
|
||||
|
||||
extern uint8_t TouchPack[36];
|
||||
extern bool StartUp;
|
||||
extern uint8_t inByte;
|
||||
|
||||
void ws_start(); //public
|
||||
|
||||
void ws_touchThreadLoop();
|
||||
|
||||
void ws_sendTouchState();
|
||||
|
||||
void ws_readHead();
|
||||
|
||||
void ws_sendResp(char importantNextReadData);
|
||||
|
||||
void ws_getTouchPack();
|
||||
|
||||
void ws_sendTouch();
|
||||
|
||||
void ws_setTouch0Data(uint32_t touchSegment0); //public
|
||||
|
||||
void ws_setTouch1Data(uint32_t touchSegment1); //public
|
||||
|
||||
void ws_setTouch2Data(uint32_t touchSegment2); //public
|
||||
|
||||
void ws_setTouch3Data(uint32_t touchSegment3); //public
|
||||
|
||||
void ws_setTouch4Data(uint32_t touchSegment4); //public
|
||||
|
||||
void ws_setTouch5Data(uint32_t touchSegment5); //public
|
||||
|
||||
void ws_setTouchData(uint32_t touchSegment0, uint32_t touchSegment1, uint32_t touchSegment2, uint32_t touchSegment3, uint32_t touchSegment4, uint32_t touchSegment5); //public
|
||||
|
||||
inline uint8_t bh_calcChecksum(uint8_t * bytes, int length) {
|
||||
uint8_t checkSum = 0x00;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
checkSum ^= *(bytes + i);
|
||||
}
|
||||
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(PICO_SDK_FETCH_FROM_GIT on)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(WaccaTouchPanel)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(wacca_touch_panel
|
||||
main.c
|
||||
mpr121.h
|
||||
mpr121.c
|
||||
)
|
||||
|
||||
# Add pico_stdlib library which aggregates commonly used features
|
||||
target_link_libraries(wacca_touch_panel
|
||||
pico_stdlib
|
||||
hardware_i2c
|
||||
)
|
||||
|
||||
# create map/bin/hex/uf2 file in addition to ELF.
|
||||
pico_add_extra_outputs(wacca_touch_panel)
|
||||
|
||||
pico_enable_stdio_usb(wacca_touch_panel 1)
|
||||
pico_enable_stdio_uart(wacca_touch_panel 0)
|
||||
@@ -0,0 +1,5 @@
|
||||
if not exist "build" mkdir build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" ..
|
||||
make wacca_touch_panel
|
||||
cd ..
|
||||
@@ -0,0 +1,5 @@
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -G "Unix Makefiles" ..
|
||||
make wacca_touch_panel
|
||||
cd ..
|
||||
@@ -0,0 +1,217 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "mpr121.h"
|
||||
|
||||
#define DEBUG_MODE // uncomment for debug messages (note: this will slow things down!)
|
||||
|
||||
#define MOTHERBOARD_I2C_PORT i2c1
|
||||
#define MOTHERBOARD_I2C_HWID 0x10 // 0x1[1-6 depending on which position it's in bottom to top]
|
||||
#define MOTHERBOARD_I2C_SDA 4
|
||||
#define MOTHERBOARD_I2C_SCL 5
|
||||
#define MOTHERBOARD_I2C_FREQ 100000
|
||||
|
||||
#define TOUCH_I2C_PORT i2c0
|
||||
#define TOUCH_I2C_SDA 6
|
||||
#define TOUCH_I2C_SCL 7
|
||||
#define INNER_MPR121_ADDR 0x5A
|
||||
#define OUTER_MPR121_ADDR 0x5B
|
||||
#define TOUCH_I2C_FREQ 100000
|
||||
#define MPR121_TOUCH_THRESHOLD 16
|
||||
#define MPR121_RELEASE_THRESHOLD 10
|
||||
|
||||
typedef enum i2c_slave_event_t {
|
||||
I2C_SLAVE_RECEIVE,
|
||||
I2C_SLAVE_REQUEST,
|
||||
I2C_SLAVE_FINISH,
|
||||
} i2c_slave_event_t;
|
||||
|
||||
// Buttons
|
||||
// [--] [--] [--] [--] [--]
|
||||
// [--] [--] [--] [--] [--]
|
||||
// [--] [--] [ ] [ ] [ ]
|
||||
// [ ] [ ] [ ] [ ] [ ]
|
||||
|
||||
struct mpr121_sensor innerSensor;
|
||||
uint16_t touchedInner = 0;
|
||||
|
||||
// Buttons
|
||||
// [ ] [ ] [ ] [ ] [ ]
|
||||
// [ ] [ ] [ ] [ ] [ ]
|
||||
// [ ] [ ] [--] [--] [--]
|
||||
// [--] [--] [--] [--] [--]
|
||||
|
||||
struct mpr121_sensor outerSensor;
|
||||
uint16_t touchedOuter = 0;
|
||||
|
||||
// Button bits
|
||||
// [ 0] [ 1] [ 2] [ 3] [ 4]
|
||||
// [ 5] [ 6] [ 7] [ 8] [ 9]
|
||||
// [10] [11] [12] [13] [14]
|
||||
// [15] [16] [17] [18] [19]
|
||||
|
||||
uint32_t previousTouchDataPacket = 0;
|
||||
bool writingPacket = false;
|
||||
uint32_t touchDataPacket = 0;
|
||||
|
||||
bool transferInProgress;
|
||||
|
||||
static inline uint8_t i2c_read_byte(i2c_inst_t *i2c) {
|
||||
i2c_hw_t *hw = i2c_get_hw(i2c);
|
||||
assert(hw->status & I2C_IC_STATUS_RFNE_BITS);
|
||||
return (uint8_t) hw->data_cmd;
|
||||
}
|
||||
|
||||
static inline void i2c_write_byte(i2c_inst_t *i2c, uint8_t value) {
|
||||
i2c_hw_t *hw = i2c_get_hw(i2c);
|
||||
assert(hw->status & I2C_IC_STATUS_TFNF_BITS);
|
||||
hw->data_cmd = value;
|
||||
}
|
||||
|
||||
static void i2cSlaveHandler(i2c_inst_t *i2c, i2c_slave_event_t event) {
|
||||
switch (event) {
|
||||
case I2C_SLAVE_RECEIVE:
|
||||
break;
|
||||
case I2C_SLAVE_REQUEST: ;
|
||||
uint32_t dataToSend = previousTouchDataPacket;
|
||||
|
||||
if (!writingPacket) dataToSend = touchDataPacket;
|
||||
|
||||
#ifdef DEBUG_MODE
|
||||
printf("Master requested packet, sending [%u]...\n", dataToSend);
|
||||
#endif
|
||||
|
||||
i2c_write_byte(MOTHERBOARD_I2C_PORT, (uint8_t) dataToSend);
|
||||
i2c_write_byte(MOTHERBOARD_I2C_PORT, (uint8_t) dataToSend >> 8);
|
||||
i2c_write_byte(MOTHERBOARD_I2C_PORT, (uint8_t) dataToSend >> 16);
|
||||
i2c_write_byte(MOTHERBOARD_I2C_PORT, (uint8_t) dataToSend >> 24);
|
||||
|
||||
break;
|
||||
case I2C_SLAVE_FINISH:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void finishTransfer() {
|
||||
if (transferInProgress) {
|
||||
i2cSlaveHandler(MOTHERBOARD_I2C_PORT, I2C_SLAVE_FINISH);
|
||||
transferInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void __not_in_flash_func(i2cSlaveI2CIRQHandler)() {
|
||||
uint32_t intrStat = MOTHERBOARD_I2C_PORT->hw->intr_stat;
|
||||
if (intrStat == 0) {
|
||||
return;
|
||||
}
|
||||
if (intrStat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) {
|
||||
MOTHERBOARD_I2C_PORT->hw->clr_tx_abrt;
|
||||
finishTransfer();
|
||||
}
|
||||
if (intrStat & I2C_IC_INTR_STAT_R_START_DET_BITS) {
|
||||
MOTHERBOARD_I2C_PORT->hw->clr_start_det;
|
||||
finishTransfer();
|
||||
}
|
||||
if (intrStat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) {
|
||||
MOTHERBOARD_I2C_PORT->hw->clr_stop_det;
|
||||
finishTransfer();
|
||||
}
|
||||
if (intrStat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
|
||||
transferInProgress = true;
|
||||
i2cSlaveHandler(MOTHERBOARD_I2C_PORT, I2C_SLAVE_RECEIVE);
|
||||
}
|
||||
if (intrStat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
|
||||
MOTHERBOARD_I2C_PORT->hw->clr_rd_req;
|
||||
transferInProgress = true;
|
||||
i2cSlaveHandler(MOTHERBOARD_I2C_PORT, I2C_SLAVE_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setupTouch() {
|
||||
i2c_init(TOUCH_I2C_PORT, TOUCH_I2C_FREQ);
|
||||
|
||||
gpio_set_function(TOUCH_I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(TOUCH_I2C_SCL, GPIO_FUNC_I2C);
|
||||
|
||||
gpio_pull_up(TOUCH_I2C_SDA);
|
||||
gpio_pull_up(TOUCH_I2C_SCL);
|
||||
|
||||
mpr121_init(TOUCH_I2C_PORT, INNER_MPR121_ADDR, &innerSensor);
|
||||
mpr121_set_thresholds(MPR121_TOUCH_THRESHOLD, MPR121_RELEASE_THRESHOLD, &innerSensor);
|
||||
|
||||
mpr121_init(TOUCH_I2C_PORT, OUTER_MPR121_ADDR, &outerSensor);
|
||||
mpr121_set_thresholds(MPR121_TOUCH_THRESHOLD, MPR121_RELEASE_THRESHOLD, &outerSensor);
|
||||
}
|
||||
|
||||
void setupMotherboard() {
|
||||
i2c_init(MOTHERBOARD_I2C_PORT, MOTHERBOARD_I2C_FREQ);
|
||||
|
||||
gpio_set_function(MOTHERBOARD_I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(MOTHERBOARD_I2C_SCL, GPIO_FUNC_I2C);
|
||||
|
||||
gpio_pull_up(MOTHERBOARD_I2C_SDA);
|
||||
gpio_pull_up(MOTHERBOARD_I2C_SCL);
|
||||
|
||||
MOTHERBOARD_I2C_PORT->hw->enable = 0;
|
||||
hw_set_bits(&MOTHERBOARD_I2C_PORT->hw->con, I2C_IC_CON_RX_FIFO_FULL_HLD_CTRL_BITS);
|
||||
MOTHERBOARD_I2C_PORT->hw->enable = 1;
|
||||
|
||||
uint i2cHardwareIndex = i2c_hw_index(MOTHERBOARD_I2C_PORT);
|
||||
i2c_set_slave_mode(MOTHERBOARD_I2C_PORT, false, MOTHERBOARD_I2C_HWID);
|
||||
|
||||
MOTHERBOARD_I2C_PORT->hw->intr_mask = I2C_IC_INTR_MASK_M_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS | I2C_IC_INTR_MASK_M_STOP_DET_BITS | I2C_IC_INTR_MASK_M_START_DET_BITS;
|
||||
|
||||
uint IRQNumber = I2C0_IRQ + i2cHardwareIndex;
|
||||
irq_set_exclusive_handler(IRQNumber, i2cSlaveI2CIRQHandler);
|
||||
irq_set_enabled(IRQNumber, true);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MODE
|
||||
#define formatButton(data, number) (((data) & (1 << (number))) ? "#" : " ")
|
||||
#define printMultiButtonRow(data1, data2, n1, n2, n3, n4, n5) printf("[%s] [%s] [%s] [%s] [%s]\n", formatButton(data1, n1), formatButton(data1, n2), formatButton(data2, n3), formatButton(data2, n4), formatButton(data2, n5))
|
||||
#define printButtonRow(data, n1, n2, n3, n4, n5) printf("[%s] [%s] [%s] [%s] [%s]\n", formatButton(data, n1), formatButton(data, n2), formatButton(data, n3), formatButton(data, n4), formatButton(data, n5))
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
printf("Wacca Touch Panel v0.1\n");
|
||||
|
||||
setupTouch();
|
||||
printf("Touch Ready\n");
|
||||
|
||||
setupMotherboard();
|
||||
printf("Communications Ready\n");
|
||||
|
||||
while(1) {
|
||||
mpr121_touched(&touchedInner, &innerSensor);
|
||||
mpr121_touched(&touchedOuter, &outerSensor);
|
||||
|
||||
touchedInner = touchedInner & 0b0000111111111111;
|
||||
touchedOuter = touchedOuter & 0b0000000011111111;
|
||||
|
||||
writingPacket = true;
|
||||
|
||||
touchDataPacket = ((uint32_t) touchedOuter << 12 | touchedInner) | 0x06900000;
|
||||
|
||||
#ifdef DEBUG_MODE
|
||||
printf("-------------------\n");
|
||||
printButtonRow(touchedInner, 0, 1, 2, 3, 4);
|
||||
printButtonRow(touchedInner, 5, 6, 7, 8, 9);
|
||||
printMultiButtonRow(touchedInner, touchedOuter, 10, 11, 0, 1, 2);
|
||||
printButtonRow(touchedOuter, 3, 4, 5, 6, 7);
|
||||
printf("-------------------\n");
|
||||
#endif
|
||||
|
||||
writingPacket = false;
|
||||
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "mpr121.h"
|
||||
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor) {
|
||||
sensor->i2c_port = i2c_port;
|
||||
sensor->i2c_addr = i2c_addr;
|
||||
|
||||
// Enter stop mode by setting ELEPROX_EN and ELE_EN bits to zero.
|
||||
// This is needed because register write operations can only take
|
||||
// place in stop mode.
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
|
||||
// Writing 0x80 (SOFT_RESET) with 0x63 asserts soft reset.
|
||||
mpr121_write(MPR121_SOFT_RESET_REG, 0x63, sensor);
|
||||
|
||||
// == Capacitance sensing settings (AN2889), Filtering and =========
|
||||
// timing settings (AN3890)
|
||||
|
||||
// These settings are configured in two registers: the Filter and
|
||||
// Global CDC CDT Configuration registers (0x5C, 0x5D).
|
||||
//
|
||||
// Charge-discharge current (CDC) and charge-discharge time (CDT)
|
||||
// can be configured globally or on a per-electrode basis. Here,
|
||||
// The global CDC and CDT values are set to their defaults, and then
|
||||
// these values are overriden by independently configuring each
|
||||
// electrode (auto-configuration).
|
||||
|
||||
// Filter/global CDC configuration register (0x5C)
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Number of samples taken
|
||||
// as input to the first level of filtering. Default is 0b00 (sets
|
||||
// samples taken to 6)
|
||||
//
|
||||
// Charge-discharge current (CDC), bits 5-0. Sets the value of
|
||||
// charge-discharge current applied to the electrode. Max is 63 µA
|
||||
// in 1 µA steps. Default is 0b010000 (16 µA)
|
||||
//
|
||||
// AFE configuration register default, 0b00010000 = 0x10
|
||||
mpr121_write(MPR121_AFE_CONFIG_REG, 0x10, sensor);
|
||||
|
||||
// Filter/global CDC configuration register (0x5D)
|
||||
//
|
||||
// Charge discharge time (CDT), bits 7-5. Selects the global value
|
||||
// of charge time applied to electrode. The maximum is 32 μs,
|
||||
// programmable as 2^(n-2) μs. Default is 0b001 (time is set to
|
||||
// 0.5 µs)
|
||||
//
|
||||
// Second filter iterations (SFI), bits 4-3. Selects the number of
|
||||
// samples taken for the second level filter. Default is 0b00
|
||||
// (number of samples is set to 4)
|
||||
//
|
||||
// Electrode sample interval (ESI), bits 2-0. Controls the sampling
|
||||
// rate of the device. The maximum is 128 ms, programmable to 2^n
|
||||
// ms. Decrease this value for better response time, increase to
|
||||
// save power. Default is 0b100 (period set to 16 ms).
|
||||
//
|
||||
// Filter configuration register default, 0b00100100 = 0x24
|
||||
// I do not need power saving features but I want fast responses,
|
||||
// so I set this to 0x20.
|
||||
mpr121_write(MPR121_FILTER_CONFIG_REG, 0x20, sensor);
|
||||
|
||||
// Auto-configuration
|
||||
//
|
||||
// Sets automatically charge current (CDC) and time (CDT) values for
|
||||
// each electrode.
|
||||
//
|
||||
// Autoconfig USL register: the upper limit for the
|
||||
// auto-configuration. This value (and those that follow below)
|
||||
// were calculated based on Vdd = 3.3 V and following the equations
|
||||
// in NXP Application Note AN3889.
|
||||
// USL = 201 = 0xC9
|
||||
mpr121_write(MPR121_AUTOCONFIG_USL_REG, 0xC9, sensor);
|
||||
|
||||
// Autoconfig target level register: the target level for the
|
||||
// auto-configuration baseline search.
|
||||
// TL = 181 = 0xB5
|
||||
mpr121_write(MPR121_AUTOCONFIG_TARGET_REG, 0xB5, sensor);
|
||||
|
||||
// Autoconfig LSL register: the lower limit for the
|
||||
// auto-configuration.
|
||||
// LSL = 131 = 0x83
|
||||
mpr121_write(MPR121_AUTOCONFIG_LSL_REG, 0x83, sensor);
|
||||
|
||||
// Autoconfiguration control register. Default value is 0b00001011 =
|
||||
// 0x0B, where:
|
||||
//
|
||||
// First filter iterations (FFI), bits 7-6. Must be the same value
|
||||
// of FFI as in register MPR121_AFE_CONFIG_REG (0x5C) above;
|
||||
// default is 0b00.
|
||||
//
|
||||
// Retry, bits 5-4. Default is disabled, 0b00.
|
||||
//
|
||||
// Baseline value adjust (BVA), bits 3-2. This value must be the
|
||||
// same as the CL (calibration lock) value in the Electrode
|
||||
// Configuration Register, below, i.e. 0b10.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ARE), bit 1. Default is 0b1,
|
||||
// enabled.
|
||||
//
|
||||
// Automatic Reconfiguration Enable (ACE), bit 0. Default is 0b1,
|
||||
// enabled.
|
||||
mpr121_write(MPR121_AUTOCONFIG_CONTROL_0_REG, 0x0B, sensor);
|
||||
|
||||
// == Baseline system (AN3891) =====================================
|
||||
|
||||
// Maximum Half Delta (MHD): Determines the largest magnitude of
|
||||
// variation to pass through the baseline filter. The range of the
|
||||
// effective value is 1~63.
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
|
||||
// Noise Half Delta (NHD): Determines the incremental change when
|
||||
// non-noise drift is detected. The range of the effective value is
|
||||
// 1~63.
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, 0x01, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, 0x01, sensor);
|
||||
|
||||
// Noise Count Limit (NCL): Determines the number of samples
|
||||
// consecutively greater than the Max Half Delta value. This is
|
||||
// necessary to determine that it is not noise. The range of the
|
||||
// effective value is 0~255.
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, 0xFF, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// Filter Delay Count Limit (FDL): Determines the operation rate of
|
||||
// the filter. A larger count limit means the filter delay is
|
||||
// operating more slowly. The range of the effective value is 0~255.
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, 0x02, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, 0x00, sensor);
|
||||
|
||||
// == Debounce and thresholds (AN3892) =============================
|
||||
|
||||
// Debounce. Value range for each is 0~7.
|
||||
// Bits 2-0, debounce touch (DT).
|
||||
// Bits 6-4, debounce release (DR).
|
||||
mpr121_write(MPR121_DEBOUNCE_REG, 0x00, sensor);
|
||||
|
||||
// Touch and release threshold values for all electrodes.
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, 0x0F, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, 0x0A, sensor);
|
||||
}
|
||||
|
||||
// Electrode Configuration Register (ECR, 0x5E). This must be the
|
||||
// last register to write to because setting ELEPROX_EN and/or
|
||||
// ELE_EN to non-zero puts the sensor in Run Mode.
|
||||
//
|
||||
// Calibration lock (CL), bits 7-6. The default on reset is 0b00
|
||||
// (CL enabled). Here I set this instead to 0b10 because this
|
||||
// enables baseline tracking with initial baseline value loaded
|
||||
// with the 5 high bits of the first electrode data value, which
|
||||
// makes the sensor stabilise sooner. Note that ths value must
|
||||
// match BVA bits in the Auto-configure Control Register above.
|
||||
//
|
||||
// Proximity enable (ELEPROX_EN), bits 5-4. Default, 0b00
|
||||
// (proximity detection disabled).
|
||||
//
|
||||
// Electrode enabled (ELE_EN), bits 3-0. Default, 0b1100 (enable
|
||||
// all 12 electrodes).
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x8C, sensor);
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Antonio González
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _MPR121_H_
|
||||
#define _MPR121_H_
|
||||
|
||||
#include "pico.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
/** \file mpr121.h
|
||||
* \brief Library for using an MPR121-based touch sensor with the
|
||||
* Raspberry Pi Pico
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct mpr121_sensor {
|
||||
i2c_inst_t *i2c_port;
|
||||
uint8_t i2c_addr;
|
||||
// uint8_t i2c_sda;
|
||||
// uint8_t ic2_scl;
|
||||
} mpr121_sensor_t;
|
||||
|
||||
/*! \brief MPR121 register map
|
||||
*/
|
||||
enum mpr121_register {
|
||||
MPR121_TOUCH_STATUS_REG = 0x00u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_0_REG = 0x02u,
|
||||
MPR121_OUT_OF_RANGE_STATUS_1_REG = 0x03u,
|
||||
MPR121_ELECTRODE_FILTERED_DATA_REG = 0x04u,
|
||||
MPR121_BASELINE_VALUE_REG = 0x1Eu,
|
||||
// Registers 0x2B ~ 0x7F are control and configuration registers
|
||||
MPR121_MAX_HALF_DELTA_RISING_REG = 0x2Bu,
|
||||
MPR121_NOISE_HALF_DELTA_RISING_REG = 0x2Cu,
|
||||
MPR121_NOISE_COUNT_LIMIT_RISING_REG = 0x2Du,
|
||||
MPR121_FILTER_DELAY_COUNT_RISING_REG = 0x2Eu,
|
||||
MPR121_MAX_HALF_DELTA_FALLING_REG = 0x2Fu,
|
||||
MPR121_NOISE_HALF_DELTA_FALLING_REG = 0x30u,
|
||||
MPR121_NOISE_COUNT_LIMIT_FALLING_REG = 0x31u,
|
||||
MPR121_FILTER_DELAY_COUNT_FALLING_REG = 0x32u,
|
||||
MPR121_NOISE_HALF_DELTA_TOUCHED_REG = 0x33u,
|
||||
MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG = 0x34u,
|
||||
MPR121_FILTER_DELAY_COUNT_TOUCHED_REG = 0x35u,
|
||||
// (ELEPROX 0x36 .. 0x40)
|
||||
MPR121_TOUCH_THRESHOLD_REG = 0x41u,
|
||||
MPR121_RELEASE_THRESHOLD_REG = 0x42u,
|
||||
// (ELEPROX 0x59 .. 0x5A)
|
||||
MPR121_DEBOUNCE_REG = 0x5Bu,
|
||||
MPR121_AFE_CONFIG_REG = 0x5Cu,
|
||||
MPR121_FILTER_CONFIG_REG = 0x5Du,
|
||||
MPR121_ELECTRODE_CONFIG_REG = 0x5Eu,
|
||||
MPR121_ELECTRODE_CURRENT_REG = 0x5Fu,
|
||||
MPR121_ELECTRODE_CHARGE_TIME_REG = 0x6Cu,
|
||||
MPR121_GPIO_CTRL_0_REG = 0x73u,
|
||||
MPR121_GPIO_CTRL_1_REG = 0x74u,
|
||||
MPR121_GPIO_DATA_REG = 0x75u,
|
||||
MPR121_GPIO_DIRECTION_REG = 0x76u,
|
||||
MPR121_GPIO_ENABLE_REG = 0x77u,
|
||||
MPR121_GPIO_DATA_SET_REG = 0x78u,
|
||||
MPR121_GPIO_DATA_CLEAR_REG = 0x79u,
|
||||
MPR121_GPIO_DATA_TOGGLE_REG = 0x7Au,
|
||||
MPR121_AUTOCONFIG_CONTROL_0_REG = 0x7Bu,
|
||||
MPR121_AUTOCONFIG_CONTROL_1_REG = 0x7Cu,
|
||||
MPR121_AUTOCONFIG_USL_REG = 0x7Du,
|
||||
MPR121_AUTOCONFIG_LSL_REG = 0x7Eu,
|
||||
MPR121_AUTOCONFIG_TARGET_REG = 0x7Fu,
|
||||
MPR121_SOFT_RESET_REG = 0x80u
|
||||
};
|
||||
|
||||
/*! \brief Initialise the MPR121 and configure registers
|
||||
*
|
||||
* The default parameters used here to configure the sensor are as in
|
||||
* the MPR121 Quick Start Guide (AN3944).
|
||||
*
|
||||
* \param i2c_port The I2C instance, either i2c0 or i2c1
|
||||
* \param i2c_addr The I2C address of the MPR121 device
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
void mpr121_init(i2c_inst_t *i2c_port, uint8_t i2c_addr,
|
||||
mpr121_sensor_t *sensor);
|
||||
|
||||
/*! \brief Write a value to the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param val The value to write
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_write(enum mpr121_register reg, uint8_t val,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t buf[] = {reg, val};
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, buf, 2,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a byte from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read(enum mpr121_register reg, uint8_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, dst, 1,
|
||||
false);
|
||||
}
|
||||
|
||||
/*! \brief Read a 2-byte value from the specified register
|
||||
*
|
||||
* \param reg The register address
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_read16(enum mpr121_register reg, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t vals[2];
|
||||
i2c_write_blocking(sensor->i2c_port, sensor->i2c_addr, ®, 1,
|
||||
true);
|
||||
i2c_read_blocking(sensor->i2c_port, sensor->i2c_addr, vals, 2,
|
||||
false);
|
||||
*dst = vals[1] << 8 | vals[0];
|
||||
}
|
||||
|
||||
/*! \brief Set touch and release thresholds
|
||||
*
|
||||
* From the MPR121 datasheet (section 5.6):
|
||||
* > In a typical application, touch threshold is in the range 4--16,
|
||||
* > and it is several counts larger than the release threshold. This
|
||||
* > is to provide hysteresis and to prevent noise and jitter.
|
||||
*
|
||||
* \param touch Touch threshold in the range 0--255
|
||||
* \param release Release threshold in the range 0--255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_thresholds(uint8_t touch, uint8_t release,
|
||||
mpr121_sensor_t *sensor) {
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
if (config != 0){
|
||||
// Stop mode
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<12; i++) {
|
||||
mpr121_write(MPR121_TOUCH_THRESHOLD_REG + i * 2, touch, sensor);
|
||||
mpr121_write(MPR121_RELEASE_THRESHOLD_REG + i * 2, release,
|
||||
sensor);
|
||||
}
|
||||
|
||||
if (config != 0){
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Enable only the number of electrodes specified
|
||||
*
|
||||
* \param nelec Number of electrodes to enable
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* E.g. if `nelec` is 3, electrodes 0 to 2 will be enabled; if `nelec`
|
||||
* is 6, electrodes 0 to 5 will be enabled. From the datasheet:
|
||||
* "Enabling specific channels will save the scan time and sensing
|
||||
* field power spent on the unused channels."
|
||||
*/
|
||||
static void mpr121_enable_electrodes(uint8_t nelec,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
|
||||
// Clear bits 3-0, which controls the operation of the 12
|
||||
// electrodes.
|
||||
config &= ~0x0f;
|
||||
|
||||
// Set number of electrodes enabled
|
||||
config |= nelec;
|
||||
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Read the touch/release status of all 13 input channels
|
||||
*
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* In the value read, bits 11-0 represent electrodes 11 to 0,
|
||||
* respectively, and bit 12 is the proximity detection channel. Each
|
||||
* bit represent the status of these channels: 1 if the channel is
|
||||
* touched, 0 if it is released.
|
||||
*/
|
||||
static void mpr121_touched(uint16_t *dst, mpr121_sensor_t *sensor) {
|
||||
mpr121_read16(MPR121_TOUCH_STATUS_REG, dst, sensor);
|
||||
*dst &= 0x0fff;
|
||||
}
|
||||
|
||||
/*! \brief Determine whether an electrode has been touched
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_is_touched(uint8_t electrode, bool *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint16_t touched;
|
||||
mpr121_touched(&touched, sensor);
|
||||
*dst = (bool) ((touched >> electrode) & 1);
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's filtered data value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* The data range of the filtered data is 0 to 1024.
|
||||
* \sa mpr121_baseline_value
|
||||
*/
|
||||
static void mpr121_filtered_data(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
mpr121_read16(MPR121_ELECTRODE_FILTERED_DATA_REG + (electrode * 2),
|
||||
dst, sensor);
|
||||
// Filtered data is 10-bit
|
||||
*dst &= 0x3ff;
|
||||
}
|
||||
|
||||
/*! \brief Read an electrode's baseline value
|
||||
*
|
||||
* \param electrode Electrode number
|
||||
* \param dst Pointer to buffer to receive data
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*
|
||||
* From the MPR112 datasheet:
|
||||
* > Along with the 10-bit electrode filtered data output, each channel
|
||||
* > also has a 10-bit baseline value. These values are the output of
|
||||
* > the internal baseline filter operation tracking the slow-voltage
|
||||
* > variation of the background capacitance change. Touch/release
|
||||
* > detection is made based on the comparison between the 10-bit
|
||||
* > electrode filtered data and the 10-bit baseline value.
|
||||
*
|
||||
* > Although internally the baseline value is 10-bit, users can only
|
||||
* > access the 8 MSB of the 10-bit baseline value through the baseline
|
||||
* > value registers.
|
||||
*
|
||||
* \sa mpr121_filtered_data
|
||||
*/
|
||||
static void mpr121_baseline_value(uint8_t electrode, uint16_t *dst,
|
||||
mpr121_sensor_t *sensor){
|
||||
uint8_t baseline;
|
||||
mpr121_read(MPR121_BASELINE_VALUE_REG + electrode, &baseline,
|
||||
sensor);
|
||||
// From the datasheet: Although internally the baseline value is
|
||||
// 10-bit, users can only access the 8 MSB of the 10-bit baseline
|
||||
// value through the baseline value registers. The read out from the
|
||||
// baseline register must be left shift two bits before comparing it
|
||||
// with the 10-bit electrode data.
|
||||
*dst = baseline << 2;
|
||||
}
|
||||
|
||||
/*! \brief Set the Max Half Delta
|
||||
*
|
||||
* The Max Half Delta determines the largest magnitude of variation to
|
||||
* pass through the third level filter. See application note MPR121
|
||||
* Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_max_half_delta(uint8_t rising, uint8_t falling,
|
||||
mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write MHD values
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_MAX_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Half Delta
|
||||
*
|
||||
* The Noise Half Delta determines the incremental change when
|
||||
* non-noise drift is detected. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 1~63
|
||||
* \param falling Value in the range 1~63
|
||||
* \param touched Value in the range 1~63
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_half_delta(uint8_t rising, uint8_t falling,
|
||||
uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write NHD values
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_HALF_DELTA_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Noise Count Limit
|
||||
*
|
||||
* The Noise Count Limit determines the number of samples consecutively
|
||||
* greater than the Max Half Delta necessary before it can be
|
||||
* determined that it is non-noise. See application note MPR121 Baseline
|
||||
* System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_noise_count_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new NCL values
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_FALLING_REG, falling, sensor);
|
||||
mpr121_write(MPR121_NOISE_COUNT_LIMIT_TOUCHED_REG, touched, sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
/*! \brief Set the Filter Delay Limit
|
||||
*
|
||||
* The Filter Delay Limit determines the rate of operation of the
|
||||
* filter. A larger number makes it operate slower. See application
|
||||
* note MPR121 Baseline System (AN3891) for details.
|
||||
*
|
||||
* \param rising Value in the range 0~255
|
||||
* \param falling Value in the range 0~255
|
||||
* \param touched Value in the range 0~255
|
||||
* \param sensor Pointer to the structure that stores the MPR121 info
|
||||
*/
|
||||
static void mpr121_set_filter_delay_limit(uint8_t rising,
|
||||
uint8_t falling, uint8_t touched, mpr121_sensor_t *sensor) {
|
||||
// Read current configuration then enter stop mode
|
||||
uint8_t config;
|
||||
mpr121_read(MPR121_ELECTRODE_CONFIG_REG, &config, sensor);
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, 0x00, sensor);
|
||||
// Write new FDL values
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_RISING_REG, rising, sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_FALLING_REG, falling,
|
||||
sensor);
|
||||
mpr121_write(MPR121_FILTER_DELAY_COUNT_TOUCHED_REG, touched,
|
||||
sensor);
|
||||
// Re-enable electrodes
|
||||
mpr121_write(MPR121_ELECTRODE_CONFIG_REG, config, sensor);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/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})
|
||||
Reference in New Issue
Block a user