add interfaces to default mode, all works except I2C, also tempsense active/addr conf has to be readded thru new usb vnd itf
This commit is contained in:
parent
200eee8074
commit
779c5e98f4
|
@ -56,11 +56,11 @@ endif()
|
|||
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libco/libco.S
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/unique.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/modeset.c
|
||||
|
@ -68,8 +68,15 @@ target_sources(${PROJECT} PUBLIC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/tusb_plt.S
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vnd_cfg.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/0def.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default2/0def.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/_default.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/cdc_serprog.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/tempsensor.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/vnd_i2ctinyusb.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/cdc_uart.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/i2c_tinyusb.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/spi_serprog.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/tempsensor.c
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/m_default2/0def.c
|
||||
)
|
||||
if(USE_USBCDC_FOR_STDIO)
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
|
@ -79,13 +86,13 @@ endif()
|
|||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libco/
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||
|
||||
add_custom_target(fix_db ALL WORKING_DIRECTORY ${OUTPUT_DIR}
|
||||
|
|
|
@ -0,0 +1,627 @@
|
|||
// vim: set et:
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Peter Lawrence
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This DAP_config provides a CMSIS-DAP alternative to picoprobe and raspberrypi-swd.cfg
|
||||
*/
|
||||
|
||||
#ifndef __DAP_CONFIG_H__
|
||||
#define __DAP_CONFIG_H__
|
||||
|
||||
//**************************************************************************************************
|
||||
/**
|
||||
\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information
|
||||
\ingroup DAP_ConfigIO_gr
|
||||
@{
|
||||
Provides definitions about the hardware and configuration of the Debug Unit.
|
||||
|
||||
This information includes:
|
||||
- Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit.
|
||||
- Debug Unit Identification strings (Vendor, Product, Serial Number).
|
||||
- Debug Unit communication packet size.
|
||||
- Debug Access Port supported modes and settings (JTAG/SWD and SWO).
|
||||
- Optional information about a connected Target Device (for Evaluation Boards).
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/regs/io_bank0.h>
|
||||
#include <hardware/regs/pads_bank0.h>
|
||||
#include <hardware/regs/resets.h>
|
||||
#include <hardware/regs/sio.h>
|
||||
#include <hardware/structs/iobank0.h>
|
||||
#include <hardware/structs/padsbank0.h>
|
||||
#include <hardware/structs/resets.h>
|
||||
#include <hardware/structs/sio.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
#include "bsp/board.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
#include "info.h"
|
||||
#include "util.h"
|
||||
#include "m_default/bsp-feature.h"
|
||||
#include "m_default/pinout.h"
|
||||
|
||||
#define PINOUT_SWCLK PINOUT_JTAG_TCK
|
||||
#define PINOUT_SWDIO PINOUT_JTAG_TMS
|
||||
|
||||
#define PINOUT_SWCLK_MASK (1UL << PINOUT_SWCLK)
|
||||
#define PINOUT_SWDIO_MASK (1UL << PINOUT_SWDIO)
|
||||
|
||||
#define PINOUT_TCK_MASK (1UL << PINOUT_JTAG_TCK)
|
||||
#define PINOUT_TMS_MASK (1UL << PINOUT_JTAG_TMS)
|
||||
#define PINOUT_TDI_MASK (1UL << PINOUT_JTAG_TDI)
|
||||
#define PINOUT_TDO_MASK (1UL << PINOUT_JTAG_TDO)
|
||||
#define PINOUT_nTRST_MASK (1UL << PINOUT_JTAG_nTRST)
|
||||
#define PINOUT_nRESET_MASK (1UL << PINOUT_JTAG_nRESET)
|
||||
|
||||
#define PINOUT_LED_MASK (1UL << PINOUT_LED)
|
||||
|
||||
/// Processor Clock of the Cortex-M MCU used in the Debug Unit.
|
||||
/// This value is used to calculate the SWD/JTAG clock speed.
|
||||
#define CPU_CLOCK 48000000U ///< Specifies the CPU Clock in Hz.
|
||||
|
||||
/// Number of processor cycles for I/O Port write operations.
|
||||
/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O
|
||||
/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors
|
||||
/// require 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses
|
||||
/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be
|
||||
/// required.
|
||||
#define IO_PORT_WRITE_CYCLES 2U ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0.
|
||||
|
||||
/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available.
|
||||
|
||||
/// Indicate that JTAG communication mode is available at the Debug Port.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available.
|
||||
|
||||
/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port.
|
||||
/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255.
|
||||
#define DAP_JTAG_DEV_CNT 8U ///< Maximum number of JTAG devices on scan chain.
|
||||
|
||||
/// Default communication mode on the Debug Access Port.
|
||||
/// Used for the command \ref DAP_Connect when Port Default mode is selected.
|
||||
#define DAP_DEFAULT_PORT 2U ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG.
|
||||
|
||||
/// Default communication speed on the Debug Access Port for SWD and JTAG mode.
|
||||
/// Used to initialize the default SWD/JTAG clock frequency.
|
||||
/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting.
|
||||
#define DAP_DEFAULT_SWJ_CLOCK 1000000U ///< Default SWD/JTAG clock frequency in Hz.
|
||||
|
||||
/// Maximum Package Size for Command and Response data.
|
||||
/// This configuration settings is used to optimize the communication performance with the
|
||||
/// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or
|
||||
/// WinUSB, 1024 for High-speed USB HID and 512 for High-speed USB WinUSB.
|
||||
#define DAP_PACKET_SIZE CFG_TUD_HID_EP_BUFSIZE ///< Specifies Packet Size in bytes.
|
||||
|
||||
/// Maximum Package Buffers for Command and Response data.
|
||||
/// This configuration settings is used to optimize the communication performance with the
|
||||
/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the
|
||||
/// setting can be reduced (valid range is 1 .. 255).
|
||||
#define DAP_PACKET_COUNT 1U ///< Specifies number of packets buffered.
|
||||
|
||||
/// Indicate that UART Serial Wire Output (SWO) trace is available.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available.
|
||||
|
||||
/// Maximum SWO UART Baudrate.
|
||||
#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz.
|
||||
|
||||
/// Indicate that Manchester Serial Wire Output (SWO) trace is available.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available.
|
||||
|
||||
/// SWO Trace Buffer Size.
|
||||
#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n).
|
||||
|
||||
/// SWO Streaming Trace.
|
||||
#define SWO_STREAM 0 ///< SWO Streaming Trace: 1 = available, 0 = not available.
|
||||
|
||||
/// Indicate that UART Communication Port is available.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available.
|
||||
|
||||
/// USART Driver instance number for the UART Communication Port.
|
||||
#define DAP_UART_DRIVER 1 ///< USART Driver instance number (Driver_USART#).
|
||||
|
||||
/// UART Receive Buffer Size.
|
||||
#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive Buffer Size in bytes (must be 2^n).
|
||||
|
||||
/// UART Transmit Buffer Size.
|
||||
#define DAP_UART_TX_BUFFER_SIZE 64U ///< Uart Transmit Buffer Size in bytes (must be 2^n).
|
||||
|
||||
/// Indicate that UART Communication via USB COM Port is available.
|
||||
/// This information is returned by the command \ref DAP_Info as part of <b>Capabilities</b>.
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define DAP_UART_USB_COM_PORT 1 ///< USB COM Port: 1 = available, 0 = not available.
|
||||
#else
|
||||
#define DAP_UART_USB_COM_PORT 0
|
||||
#endif
|
||||
|
||||
/// Clock frequency of the Test Domain Timer. Timer value is returned with \ref TIMESTAMP_GET.
|
||||
#define TIMESTAMP_CLOCK 0U ///< Timestamp clock in Hz (0 = timestamps not supported).
|
||||
|
||||
/// Debug Unit is connected to fixed Target Device.
|
||||
/// The Debug Unit may be part of an evaluation board and always connected to a fixed
|
||||
/// known device. In this case a Device Vendor and Device Name string is stored which
|
||||
/// may be used by the debugger or IDE to configure device parameters.
|
||||
#define TARGET_DEVICE_FIXED 0 ///< Target Device: 1 = known, 0 = unknown;
|
||||
|
||||
#if TARGET_DEVICE_FIXED
|
||||
#define TARGET_DEVICE_VENDOR "Raspberry Pi" ///< String indicating the Silicon Vendor
|
||||
#define TARGET_DEVICE_NAME "Pico" ///< String indicating the Target Device
|
||||
#endif
|
||||
|
||||
#include "DAP.h"
|
||||
|
||||
/** Get Vendor ID string.
|
||||
\param str Pointer to buffer to store the string.
|
||||
\return String length.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetVendorString(char* str) {
|
||||
static const char vnd[] = INFO_MANUFACTURER;
|
||||
for (size_t i = 0; i < sizeof(vnd); ++i) str[i] = vnd[i];
|
||||
return sizeof(vnd) - 1;
|
||||
}
|
||||
|
||||
/** Get Product ID string.
|
||||
\param str Pointer to buffer to store the string.
|
||||
\return String length.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetProductString(char* str) {
|
||||
static const char prd[] = INFO_PRODUCT(INFO_BOARDNAME);
|
||||
for (size_t i = 0; i < sizeof(prd); ++i) str[i] = prd[i];
|
||||
return sizeof(prd) - 1;
|
||||
}
|
||||
|
||||
/** Get Serial Number string.
|
||||
\param str Pointer to buffer to store the string.
|
||||
\return String length.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetSerNumString(char* str) { return get_unique_id_u8((uint8_t*)str); }
|
||||
|
||||
/** Get Target Device Vendor string.
|
||||
\param str Pointer to buffer to store the string (max 60 characters).
|
||||
\return String length (including terminating NULL character) or 0 (no string).
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetTargetDeviceVendorString(char* str) {
|
||||
(void)str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get Target Device Name string.
|
||||
\param str Pointer to buffer to store the string (max 60 characters).
|
||||
\return String length (including terminating NULL character) or 0 (no string).
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetTargetDeviceNameString(char* str) {
|
||||
(void)str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get Target Board Vendor string.
|
||||
\param str Pointer to buffer to store the string (max 60 characters).
|
||||
\return String length (including terminating NULL character) or 0 (no string).
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetTargetBoardVendorString(char* str) {
|
||||
(void)str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get Target Board Name string.
|
||||
\param str Pointer to buffer to store the string (max 60 characters).
|
||||
\return String length (including terminating NULL character) or 0 (no string).
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetTargetBoardNameString(char* str) {
|
||||
(void)str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO! */
|
||||
/** Get Product Firmware Version string.
|
||||
\param str Pointer to buffer to store the string (max 60 characters).
|
||||
\return String length (including terminating NULL character) or 0 (no string).
|
||||
*/
|
||||
__STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString(char* str) {
|
||||
(void)str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
//**************************************************************************************************
|
||||
/**
|
||||
\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access
|
||||
\ingroup DAP_ConfigIO_gr
|
||||
@{
|
||||
|
||||
Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode
|
||||
and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug
|
||||
interface of a device. The following I/O Pins are provided:
|
||||
|
||||
JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode
|
||||
---------------------------- | -------------------- | ---------------------------------------------
|
||||
TCK: Test Clock | SWCLK: Clock | Output Push/Pull
|
||||
TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data)
|
||||
TDI: Test Data Input | | Output Push/Pull
|
||||
TDO: Test Data Output | | Input
|
||||
nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor
|
||||
nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor
|
||||
|
||||
|
||||
DAP Hardware I/O Pin Access Functions
|
||||
-------------------------------------
|
||||
The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to
|
||||
these I/O Pins.
|
||||
|
||||
For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only.
|
||||
This functions are provided to achieve faster I/O that is possible with some advanced GPIO
|
||||
peripherals that can independently write/read a single I/O pin without affecting any other pins
|
||||
of the same I/O port. The following SWDIO I/O Pin functions are provided:
|
||||
- \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware.
|
||||
- \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware.
|
||||
- \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed.
|
||||
- \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed.
|
||||
*/
|
||||
|
||||
// Configure DAP I/O pins ------------------------------
|
||||
|
||||
/** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET.
|
||||
Configures the DAP Hardware I/O pins for JTAG mode:
|
||||
- TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level.
|
||||
- TDO to input mode.
|
||||
*/
|
||||
__STATIC_INLINE void PORT_JTAG_SETUP(void) {
|
||||
resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS);
|
||||
|
||||
/* set to default high level */
|
||||
sio_hw->gpio_oe_set = PINOUT_TCK_MASK | PINOUT_TMS_MASK | PINOUT_TDI_MASK | PINOUT_nTRST_MASK |
|
||||
PINOUT_nRESET_MASK;
|
||||
sio_hw->gpio_set = PINOUT_TCK_MASK | PINOUT_TMS_MASK | PINOUT_TDI_MASK | PINOUT_nTRST_MASK |
|
||||
PINOUT_nRESET_MASK;
|
||||
/* TDO needs to be an input */
|
||||
sio_hw->gpio_oe_clr = PINOUT_TDO_MASK;
|
||||
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TCK],
|
||||
PADS_BANK0_GPIO0_IE_BITS, // bits to set: input enable
|
||||
PADS_BANK0_GPIO0_IE_BITS |
|
||||
PADS_BANK0_GPIO0_OD_BITS); // bits to mask out: input enable, output disable
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TMS], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TDI], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TDO],
|
||||
PADS_BANK0_GPIO0_IE_BITS |
|
||||
PADS_BANK0_GPIO0_OD_BITS, // TDO needs to have its output disabled
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_nTRST], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_nRESET], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
|
||||
// NOTE: hiZ: ctrl = (ctrl & ~(CTRL_OEOVER_BITS)) | (GPIO_OVERRIDE_LOW << CTRL_OEOVER_LSB);
|
||||
// normal == 0, low == 2
|
||||
|
||||
// set pin modes to general IO (SIO)
|
||||
iobank0_hw->io[PINOUT_JTAG_TCK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_JTAG_TMS].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_JTAG_TDI].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_JTAG_TDO].ctrl = (GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB)
|
||||
/*| (GPIO_OVERRIDE_LOW << IO_BANK0_GPIO0_CTRL_OEOVER_LSB)*/;
|
||||
iobank0_hw->io[PINOUT_JTAG_nTRST].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_JTAG_nRESET].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
}
|
||||
|
||||
/** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET.
|
||||
Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode:
|
||||
- SWCLK, SWDIO, nRESET to output mode and set to default high level.
|
||||
- TDI, nTRST to HighZ mode (pins are unused in SWD mode).
|
||||
*/
|
||||
__STATIC_INLINE void PORT_SWD_SETUP(void) {
|
||||
resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS);
|
||||
|
||||
/* set to default high level */
|
||||
sio_hw->gpio_oe_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK;
|
||||
sio_hw->gpio_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK;
|
||||
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_SWCLK], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
hw_write_masked(&padsbank0_hw->io[PINOUT_SWDIO], PADS_BANK0_GPIO0_IE_BITS,
|
||||
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
iobank0_hw->io[PINOUT_SWCLK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
iobank0_hw->io[PINOUT_SWDIO].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
}
|
||||
|
||||
/** Disable JTAG/SWD I/O Pins.
|
||||
Disables the DAP Hardware I/O pins which configures:
|
||||
- TCK/SWCLK, TMS/SWDIO, TDI, TDO, nTRST, nRESET to High-Z mode.
|
||||
*/
|
||||
__STATIC_INLINE void PORT_OFF(void) {
|
||||
sio_hw->gpio_oe_clr = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK |
|
||||
PINOUT_TDI_MASK //| PINOUT_TDO_MASK
|
||||
| PINOUT_nTRST_MASK | PINOUT_nRESET_MASK;
|
||||
}
|
||||
|
||||
// SWCLK/TCK I/O pin -------------------------------------
|
||||
|
||||
/** SWCLK/TCK I/O pin: Get Input.
|
||||
\return Current status of the SWCLK/TCK DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_SWCLK_MASK) >> PINOUT_SWCLK;
|
||||
}
|
||||
|
||||
/** SWCLK/TCK I/O pin: Set Output to High.
|
||||
Set the SWCLK/TCK DAP hardware I/O pin to high level.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET(void) { sio_hw->gpio_set = PINOUT_SWCLK_MASK; }
|
||||
|
||||
/** SWCLK/TCK I/O pin: Set Output to Low.
|
||||
Set the SWCLK/TCK DAP hardware I/O pin to low level.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR(void) { sio_hw->gpio_clr = PINOUT_SWCLK_MASK; }
|
||||
|
||||
// SWDIO/TMS Pin I/O --------------------------------------
|
||||
|
||||
/** SWDIO/TMS I/O pin: Get Input.
|
||||
\return Current status of the SWDIO/TMS DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_SWDIO_MASK) >> PINOUT_SWDIO;
|
||||
}
|
||||
|
||||
/* PIN_SWDIO_TMS_SET and PIN_SWDIO_TMS_CLR are used by SWJ_Sequence */
|
||||
|
||||
/** SWDIO/TMS I/O pin: Set Output to High.
|
||||
Set the SWDIO/TMS DAP hardware I/O pin to high level.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET(void) { sio_hw->gpio_set = PINOUT_SWDIO_MASK; }
|
||||
|
||||
/** SWDIO/TMS I/O pin: Set Output to Low.
|
||||
Set the SWDIO/TMS DAP hardware I/O pin to low level.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR(void) { sio_hw->gpio_clr = PINOUT_SWDIO_MASK; }
|
||||
|
||||
/** SWDIO I/O pin: Get Input (used in SWD mode only).
|
||||
\return Current status of the SWDIO DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_SWDIO_MASK) ? 1U : 0U;
|
||||
}
|
||||
|
||||
/** SWDIO I/O pin: Set Output (used in SWD mode only).
|
||||
\param bit Output value for the SWDIO DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) {
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_SWDIO_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_SWDIO_MASK;
|
||||
}
|
||||
|
||||
/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only).
|
||||
Configure the SWDIO DAP hardware I/O pin to output mode. This function is
|
||||
called prior \ref PIN_SWDIO_OUT function calls.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { sio_hw->gpio_oe_set = PINOUT_SWDIO_MASK; }
|
||||
|
||||
/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only).
|
||||
Configure the SWDIO DAP hardware I/O pin to input mode. This function is
|
||||
called prior \ref PIN_SWDIO_IN function calls.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { sio_hw->gpio_oe_clr = PINOUT_SWDIO_MASK; }
|
||||
|
||||
// TDI Pin I/O ---------------------------------------------
|
||||
|
||||
/** TDI I/O pin: Get Input.
|
||||
\return Current status of the TDI DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_TDI_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_TDI_MASK) >> PINOUT_JTAG_TDI;
|
||||
}
|
||||
|
||||
/** TDI I/O pin: Set Output.
|
||||
\param bit Output value for the TDI DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_TDI_OUT(uint32_t bit) {
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_TDI_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_TDI_MASK;
|
||||
}
|
||||
|
||||
// TDO Pin I/O ---------------------------------------------
|
||||
|
||||
/** TDO I/O pin: Get Input.
|
||||
\return Current status of the TDO DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_TDO_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_TDO_MASK) >> PINOUT_JTAG_TDO;
|
||||
}
|
||||
|
||||
// nTRST Pin I/O -------------------------------------------
|
||||
|
||||
/** nTRST I/O pin: Get Input.
|
||||
\return Current status of the nTRST DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_nTRST_MASK) >> PINOUT_JTAG_nTRST;
|
||||
}
|
||||
|
||||
/** nTRST I/O pin: Set Output.
|
||||
\param bit JTAG TRST Test Reset pin status:
|
||||
- 0: issue a JTAG TRST Test Reset.
|
||||
- 1: release JTAG TRST Test Reset.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_nTRST_OUT(uint32_t bit) {
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_nTRST_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_nTRST_MASK;
|
||||
}
|
||||
|
||||
// nRESET Pin I/O------------------------------------------
|
||||
|
||||
/** nRESET I/O pin: Get Input.
|
||||
\return Current status of the nRESET DAP hardware I/O pin.
|
||||
*/
|
||||
__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN(void) {
|
||||
return (sio_hw->gpio_in & PINOUT_nRESET_MASK) >> PINOUT_JTAG_nRESET;
|
||||
}
|
||||
|
||||
/** nRESET I/O pin: Set Output.
|
||||
\param bit target device hardware reset pin status:
|
||||
- 0: issue a device hardware reset.
|
||||
- 1: release device hardware reset.
|
||||
*/
|
||||
__STATIC_FORCEINLINE void PIN_nRESET_OUT(uint32_t bit) {
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_nRESET_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_nRESET_MASK;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
//**************************************************************************************************
|
||||
/**
|
||||
\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs
|
||||
\ingroup DAP_ConfigIO_gr
|
||||
@{
|
||||
|
||||
CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit.
|
||||
|
||||
It is recommended to provide the following LEDs for status indication:
|
||||
- Connect LED: is active when the DAP hardware is connected to a debugger.
|
||||
- Running LED: is active when the debugger has put the target device into running state.
|
||||
*/
|
||||
|
||||
/** Debug Unit: Set status of Connected LED.
|
||||
\param bit status of the Connect LED.
|
||||
- 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit.
|
||||
- 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit.
|
||||
*/
|
||||
__STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit) {
|
||||
#if PINOUT_LED_CONNECTED
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_LED_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_LED_MASK;
|
||||
#else
|
||||
(void)bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Debug Unit: Set status Target Running LED.
|
||||
\param bit status of the Target Running LED.
|
||||
- 1: Target Running LED ON: program execution in target started.
|
||||
- 0: Target Running LED OFF: program execution in target stopped.
|
||||
*/
|
||||
__STATIC_INLINE void LED_RUNNING_OUT(uint32_t bit) {
|
||||
#if PINOUT_LED_RUNNING
|
||||
if (bit & 1)
|
||||
sio_hw->gpio_set = PINOUT_LED_MASK;
|
||||
else
|
||||
sio_hw->gpio_clr = PINOUT_LED_MASK;
|
||||
#else
|
||||
(void)bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
//**************************************************************************************************
|
||||
/**
|
||||
\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp
|
||||
\ingroup DAP_ConfigIO_gr
|
||||
@{
|
||||
Access function for Test Domain Timer.
|
||||
|
||||
The value of the Test Domain Timer in the Debug Unit is returned by the function \ref TIMESTAMP_GET.
|
||||
By default, the DWT timer is used. The frequency of this timer is configured with \ref
|
||||
TIMESTAMP_CLOCK.
|
||||
|
||||
*/
|
||||
|
||||
/** Get timestamp of Test Domain Timer.
|
||||
\return Current timestamp value.
|
||||
*/
|
||||
__STATIC_INLINE uint32_t TIMESTAMP_GET(void) {
|
||||
#if TIMESTAMP_CLOCK > 0
|
||||
return (DWT->CYCCNT);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
//**************************************************************************************************
|
||||
/**
|
||||
\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization
|
||||
\ingroup DAP_ConfigIO_gr
|
||||
@{
|
||||
|
||||
CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP.
|
||||
*/
|
||||
|
||||
/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized).
|
||||
This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the
|
||||
Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set:
|
||||
- I/O clock system enabled.
|
||||
- all I/O pins: input buffer enabled, output pins are set to HighZ mode.
|
||||
- for nTRST, nRESET a weak pull-up (if available) is enabled.
|
||||
- LED output pins are enabled and LEDs are turned off.
|
||||
*/
|
||||
__STATIC_INLINE void DAP_SETUP(void) {
|
||||
sio_hw->gpio_oe_set = PINOUT_LED_MASK;
|
||||
sio_hw->gpio_clr = PINOUT_LED_MASK;
|
||||
|
||||
hw_write_masked(
|
||||
&padsbank0_hw->io[PINOUT_LED], 0, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS);
|
||||
iobank0_hw->io[PINOUT_LED].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
|
||||
|
||||
bi_decl(bi_2pins_with_names(PINOUT_JTAG_TCK, "TCK / SWCLK", PINOUT_JTAG_TMS, "TMS / SWDIO"));
|
||||
bi_decl(bi_4pins_with_names(PINOUT_JTAG_TDI, "TDI", PINOUT_JTAG_TDO, "TDO", PINOUT_JTAG_nTRST,
|
||||
"nTRST", PINOUT_JTAG_nRESET, "nRESET"));
|
||||
}
|
||||
|
||||
/** Reset Target Device with custom specific I/O pin or command sequence.
|
||||
This function allows the optional implementation of a device specific reset sequence.
|
||||
It is called when the command \ref DAP_ResetTarget and is for example required
|
||||
when a device needs a time-critical unlock sequence that enables the debug port.
|
||||
\return 0 = no device specific reset sequence is implemented.\n
|
||||
1 = a device specific reset sequence is implemented.
|
||||
*/
|
||||
__STATIC_INLINE uint8_t RESET_TARGET(void) {
|
||||
return (0U); // change to '1' when a device reset sequence is implemented
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
#endif /* __DAP_CONFIG_H__ */
|
|
@ -0,0 +1,25 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef BSP_INFO_H_
|
||||
#define BSP_INFO_H_
|
||||
|
||||
/*#define USB_VID 0x2e8a*/ /* Raspberry Pi */
|
||||
#define USB_VID 0xcafe /* TinyUSB */
|
||||
/*#define USB_VID 0x1209*/ /* Generic */
|
||||
/*#define USB_VID 0x1d50*/ /* OpenMoko */
|
||||
#define USB_PID 0x1312
|
||||
|
||||
// TODO: other RP2040 boards
|
||||
#define INFO_BOARDNAME "RP2040 Pico"
|
||||
|
||||
/* each CFG_TUD_xxx macro must be the max across all modes */
|
||||
// TODO: have this depend on the DBOARD_HAS_xxx macros?
|
||||
#define CFG_TUD_HID 1
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define CFG_TUD_CDC 3
|
||||
#else
|
||||
#define CFG_TUD_CDC 2
|
||||
#endif
|
||||
#define CFG_TUD_VENDOR 1
|
||||
|
||||
#endif
|
|
@ -7,9 +7,7 @@
|
|||
#include <pico/stdio/driver.h>
|
||||
#include <pico/time.h>
|
||||
|
||||
//#include "pinout.h"
|
||||
//#include "protocfg.h"
|
||||
#include "tusb.h"
|
||||
#include <tusb.h>
|
||||
|
||||
#ifndef PICO_STDIO_USB_STDOUT_TIMEOUT_US
|
||||
#define PICO_STDIO_USB_STDOUT_TIMEOUT_US 500000
|
||||
|
@ -18,9 +16,13 @@
|
|||
// *mostly* the same as the SDK code, *except* we have to explicitely pass the
|
||||
// CDC interface number to the tusb functions, making the SDK code itself very
|
||||
// non-reusable >__>
|
||||
#define CDC_N_STDIO 0
|
||||
|
||||
static mutex_t stdio_usb_mutex;
|
||||
static int CDC_N_STDIO = 0;
|
||||
|
||||
void stdio_usb_set_itf_num(int itf) {
|
||||
CDC_N_STDIO = itf;
|
||||
}
|
||||
|
||||
static void stdio_usb_out_chars(const char* buf, int length) {
|
||||
static uint64_t last_avail_time;
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
#ifndef BSP_FEATURE_M_DEFAULT_H_
|
||||
#define BSP_FEATURE_M_DEFAULT_H_
|
||||
|
||||
#define DBOARD_HAS_UART
|
||||
#define DBOARD_HAS_CMSISDAP
|
||||
#define DBOARD_HAS_SERPROG
|
||||
// FIXME: this one doesn't work yet!!!!! (kernel usb device cfg fails)
|
||||
// "usb 1-1: can't set config #1, error -32"
|
||||
/*#define DBOARD_HAS_I2C*/
|
||||
/*#define DBOARD_HAS_TEMPSENSOR*/
|
||||
|
||||
#include "bsp-info.h"
|
||||
|
||||
enum {
|
||||
HID_N_CMSISDAP = 0,
|
||||
|
||||
HID_N__NITF
|
||||
};
|
||||
enum {
|
||||
CDC_N_UART = 0,
|
||||
CDC_N_SERPROG,
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
CDC_N_STDIO,
|
||||
#endif
|
||||
|
||||
CDC_N__NITF
|
||||
};
|
||||
enum {
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
VND_CFG = 0,
|
||||
#endif
|
||||
|
||||
VND_N__NITF
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// vim: set et:
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
#include "m_default/pinout.h"
|
||||
#include "m_default/cdc.h"
|
||||
|
||||
static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||
static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE];
|
||||
|
||||
void cdc_uart_init(void) {
|
||||
gpio_set_function(PINOUT_UART_TX, GPIO_FUNC_UART);
|
||||
gpio_set_function(PINOUT_UART_RX, GPIO_FUNC_UART);
|
||||
uart_init(PINOUT_UART_INTERFACE, PINOUT_UART_BAUDRATE);
|
||||
|
||||
bi_decl(bi_2pins_with_func(PINOUT_UART_TX, PINOUT_UART_RX, GPIO_FUNC_UART));
|
||||
}
|
||||
void cdc_uart_deinit(void) {
|
||||
uart_deinit(PINOUT_UART_INTERFACE);
|
||||
gpio_set_function(PINOUT_UART_TX, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_UART_RX, GPIO_FUNC_NULL);
|
||||
}
|
||||
|
||||
void cdc_uart_task(void) {
|
||||
// Consume uart fifo regardless even if not connected
|
||||
uint rx_len = 0;
|
||||
while (uart_is_readable(PINOUT_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) {
|
||||
rx_buf[rx_len++] = uart_getc(PINOUT_UART_INTERFACE);
|
||||
}
|
||||
|
||||
if (tud_cdc_n_connected(CDC_N_UART)) {
|
||||
// Do we have anything to display on the host's terminal?
|
||||
if (rx_len) {
|
||||
for (uint i = 0; i < rx_len; i++) { tud_cdc_n_write_char(CDC_N_UART, rx_buf[i]); }
|
||||
tud_cdc_n_write_flush(CDC_N_UART);
|
||||
}
|
||||
|
||||
if (tud_cdc_n_available(CDC_N_UART)) {
|
||||
// Is there any data from the host for us to tx
|
||||
uint tx_len = tud_cdc_n_read(CDC_N_UART, tx_buf, sizeof(tx_buf));
|
||||
uart_write_blocking(PINOUT_UART_INTERFACE, tx_buf, tx_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_uart_set_hwflow(bool enable) { uart_set_hw_flow(PINOUT_UART_INTERFACE, enable, enable); }
|
||||
|
||||
void cdc_uart_set_baudrate(uint32_t brate) { uart_init(PINOUT_UART_INTERFACE, brate); }
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/i2c.h>
|
||||
#include <hardware/resets.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/timeout_helper.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
#include "m_default/pinout.h"
|
||||
|
||||
#include "m_default/i2ctinyusb.h"
|
||||
|
||||
static int delay = 10, delay2 = 5;
|
||||
|
||||
// I2C bitbang reimpl because ugh, synopsys
|
||||
// (mostly inspired by original I2CTinyUSB AVR firmware)
|
||||
__attribute__((__always_inline__)) inline static void i2cio_set_sda(bool hi) {
|
||||
if (hi) {
|
||||
sio_hw->gpio_oe_clr = (1 << PINOUT_I2C_SDA); // SDA is input
|
||||
// => pullup configured, so it'll go high
|
||||
} else {
|
||||
sio_hw->gpio_oe_set = (1 << PINOUT_I2C_SDA); // SDA is output
|
||||
sio_hw->gpio_clr = (1 << PINOUT_I2C_SDA); // and drive it low
|
||||
}
|
||||
}
|
||||
__attribute__((__always_inline__)) inline static bool i2cio_get_sda(void) {
|
||||
return (sio_hw->gpio_in & (1 << PINOUT_I2C_SDA)) != 0;
|
||||
}
|
||||
__attribute__((__always_inline__)) inline static void i2cio_set_scl(bool hi) {
|
||||
busy_wait_us_32(delay2);
|
||||
sio_hw->gpio_oe_set = (1 << PINOUT_I2C_SCL); // SCL is output
|
||||
if (hi)
|
||||
sio_hw->gpio_set = (1 << PINOUT_I2C_SCL); // SCL is high
|
||||
else
|
||||
sio_hw->gpio_clr = (1 << PINOUT_I2C_SCL); // SCL is low
|
||||
busy_wait_us_32(delay2);
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) inline static void i2cio_scl_toggle(void) {
|
||||
i2cio_set_scl(true);
|
||||
i2cio_set_scl(false);
|
||||
}
|
||||
|
||||
static void __no_inline_not_in_flash_func(i2cio_start)(void) { // start condition
|
||||
i2cio_set_sda(false);
|
||||
i2cio_set_scl(false);
|
||||
}
|
||||
static void __no_inline_not_in_flash_func(i2cio_repstart)(void) { // repstart condition
|
||||
i2cio_set_sda(true);
|
||||
i2cio_set_scl(true);
|
||||
|
||||
i2cio_set_sda(false);
|
||||
i2cio_set_scl(false);
|
||||
}
|
||||
static void __no_inline_not_in_flash_func(i2cio_stop)(void) { // stop condition
|
||||
i2cio_set_sda(false);
|
||||
i2cio_set_scl(true);
|
||||
i2cio_set_sda(true);
|
||||
}
|
||||
|
||||
static bool __no_inline_not_in_flash_func(i2cio_write7)(
|
||||
uint8_t v) { // return value: acked? // needed for 10bitaddr xfers
|
||||
for (int i = 6; i >= 0; --i) {
|
||||
i2cio_set_sda((v & (1 << i)) != 0);
|
||||
i2cio_scl_toggle();
|
||||
}
|
||||
|
||||
i2cio_set_sda(true);
|
||||
i2cio_set_scl(true);
|
||||
|
||||
bool ack = !i2cio_get_sda();
|
||||
i2cio_set_scl(false);
|
||||
|
||||
return ack;
|
||||
}
|
||||
static bool __no_inline_not_in_flash_func(i2cio_write8)(uint8_t v) { // return value: acked?
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
i2cio_set_sda((v & (1 << i)) != 0);
|
||||
i2cio_scl_toggle();
|
||||
}
|
||||
|
||||
i2cio_set_sda(true);
|
||||
i2cio_set_scl(true);
|
||||
|
||||
bool ack = !i2cio_get_sda();
|
||||
i2cio_set_scl(false);
|
||||
|
||||
return ack;
|
||||
}
|
||||
static uint8_t __no_inline_not_in_flash_func(i2cio_read8)(bool last) {
|
||||
i2cio_set_sda(true);
|
||||
i2cio_set_scl(false);
|
||||
|
||||
uint8_t rv = 0;
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
i2cio_set_scl(true);
|
||||
bool c = i2cio_get_sda();
|
||||
rv <<= 1;
|
||||
if (c) rv |= 1;
|
||||
i2cio_set_scl(false);
|
||||
}
|
||||
|
||||
if (last)
|
||||
i2cio_set_sda(true);
|
||||
else
|
||||
i2cio_set_sda(false);
|
||||
|
||||
i2cio_scl_toggle();
|
||||
i2cio_set_sda(true);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// replicating/rewriting some SDK functions because they don't do what I want
|
||||
// so I'm making better ones
|
||||
|
||||
static int __no_inline_not_in_flash_func(i2cex_probe_address)(uint16_t addr, bool a10bit) {
|
||||
// I2C pins to SIO
|
||||
gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_SIO);
|
||||
gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_SIO);
|
||||
|
||||
int rv;
|
||||
i2cio_start();
|
||||
|
||||
if (a10bit) {
|
||||
// A10 magic higher 2 addr bits r/#w bit
|
||||
uint8_t addr1 = 0x70 | (((addr >> 8) & 3) << 1) | 0, addr2 = addr & 0xff;
|
||||
|
||||
if (i2cio_write7(addr1)) {
|
||||
if (i2cio_write8(addr2))
|
||||
rv = 0;
|
||||
else
|
||||
rv = PICO_ERROR_GENERIC;
|
||||
} else
|
||||
rv = PICO_ERROR_GENERIC;
|
||||
} else {
|
||||
if (i2cio_write8((addr << 1) & 0xff))
|
||||
rv = 0; // acked: ok
|
||||
else
|
||||
rv = PICO_ERROR_GENERIC; // nak :/
|
||||
}
|
||||
i2cio_stop();
|
||||
|
||||
// I2C back to I2C
|
||||
gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C);
|
||||
gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline static void i2cex_abort_xfer(i2c_inst_t* i2c) {
|
||||
#if 1
|
||||
// may be bugged??? so doesnt do anything for now
|
||||
(void)i2c;
|
||||
return;
|
||||
#else
|
||||
// now do the abort
|
||||
i2c->hw->enable = 1 /*| (1<<2)*/ | (1 << 1);
|
||||
// wait for M_TX_ABRT irq
|
||||
do {
|
||||
/*if (timeout_check) {
|
||||
timeout = timeout_check(ts);
|
||||
abort |= timeout;
|
||||
}*/
|
||||
tight_loop_contents();
|
||||
} while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS));
|
||||
// reset irq
|
||||
// if (!timeout)
|
||||
(void)i2c->hw->clr_tx_abrt;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
|
||||
const uint8_t* src, size_t len, bool nostop, absolute_time_t until) {
|
||||
timeout_state_t ts_;
|
||||
|
||||
struct timeout_state* ts = &ts_;
|
||||
|
||||
check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until);
|
||||
|
||||
if ((int)len < 0) return PICO_ERROR_GENERIC;
|
||||
if (a10bit) { // addr too high
|
||||
if (addr & ~(uint16_t)((1 << 10) - 1)) return PICO_ERROR_GENERIC;
|
||||
} else if (addr & 0x80)
|
||||
return PICO_ERROR_GENERIC;
|
||||
|
||||
if (len == 0) return i2cex_probe_address(addr, a10bit);
|
||||
|
||||
bool abort = false, timeout = false;
|
||||
uint32_t abort_reason = 0;
|
||||
int byte_ctr;
|
||||
|
||||
i2c->hw->enable = 0;
|
||||
// enable 10bit mode if requested
|
||||
// clang-format off
|
||||
hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS,
|
||||
(a10bit ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS
|
||||
: I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS)
|
||||
<< I2C_IC_CON_IC_10BITADDR_MASTER_LSB);
|
||||
// clang-format on
|
||||
i2c->hw->tar = addr;
|
||||
i2c->hw->enable = 1;
|
||||
|
||||
for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) {
|
||||
bool first = byte_ctr == 0, last = byte_ctr == (int)len - 1;
|
||||
|
||||
i2c->hw->data_cmd = (bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB)
|
||||
| (bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB)
|
||||
| *src++;
|
||||
|
||||
do {
|
||||
if (timeout_check) {
|
||||
timeout = timeout_check(ts);
|
||||
abort |= timeout;
|
||||
}
|
||||
tight_loop_contents();
|
||||
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS));
|
||||
|
||||
if (!timeout) {
|
||||
abort_reason = i2c->hw->tx_abrt_source;
|
||||
if (abort_reason) {
|
||||
(void)i2c->hw->clr_tx_abrt;
|
||||
abort = true;
|
||||
}
|
||||
|
||||
if (abort || (last && !nostop)) {
|
||||
do {
|
||||
if (timeout_check) {
|
||||
timeout = timeout_check(ts);
|
||||
abort |= timeout;
|
||||
}
|
||||
tight_loop_contents();
|
||||
// clang-format off
|
||||
} while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS));
|
||||
// clang-format on
|
||||
|
||||
if (!timeout)
|
||||
(void)i2c->hw->clr_stop_det;
|
||||
else
|
||||
// if we had a timeout, send an abort request to the hardware,
|
||||
// so that the bus gets released
|
||||
i2cex_abort_xfer(i2c);
|
||||
}
|
||||
} else
|
||||
i2cex_abort_xfer(i2c);
|
||||
|
||||
if (abort) break;
|
||||
}
|
||||
|
||||
int rval;
|
||||
|
||||
if (abort) {
|
||||
// clang-format off
|
||||
const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS
|
||||
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS
|
||||
| I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS;
|
||||
// clang-format on
|
||||
|
||||
if (timeout)
|
||||
rval = PICO_ERROR_TIMEOUT;
|
||||
else if (!abort_reason || (abort_reason & addr_noack))
|
||||
rval = PICO_ERROR_GENERIC;
|
||||
else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS)
|
||||
rval = byte_ctr;
|
||||
else
|
||||
rval = PICO_ERROR_GENERIC;
|
||||
} else
|
||||
rval = byte_ctr;
|
||||
|
||||
i2c->restart_on_next = nostop;
|
||||
return rval;
|
||||
}
|
||||
static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, uint8_t* dst,
|
||||
size_t len, bool nostop, absolute_time_t until) {
|
||||
timeout_state_t ts_;
|
||||
struct timeout_state* ts = &ts_;
|
||||
check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until);
|
||||
|
||||
if ((int)len < 0) return PICO_ERROR_GENERIC;
|
||||
if (a10bit) { // addr too high
|
||||
if (addr & ~(uint16_t)((1 << 10) - 1)) return PICO_ERROR_GENERIC;
|
||||
} else if (addr & 0x80)
|
||||
return PICO_ERROR_GENERIC;
|
||||
|
||||
i2c->hw->enable = 0;
|
||||
// enable 10bit mode if requested
|
||||
hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS,
|
||||
(a10bit ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS
|
||||
: I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS)
|
||||
<< I2C_IC_CON_IC_10BITADDR_MASTER_LSB);
|
||||
i2c->hw->tar = addr;
|
||||
i2c->hw->enable = 1;
|
||||
|
||||
if (len == 0) return i2cex_probe_address(addr, a10bit);
|
||||
|
||||
bool abort = false, timeout = false;
|
||||
uint32_t abort_reason = 0;
|
||||
int byte_ctr;
|
||||
|
||||
for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) {
|
||||
bool first = byte_ctr == 0;
|
||||
bool last = byte_ctr == (int)len - 1;
|
||||
|
||||
while (!i2c_get_write_available(i2c) && !abort) {
|
||||
tight_loop_contents();
|
||||
// ?
|
||||
if (timeout_check) {
|
||||
timeout = timeout_check(ts);
|
||||
abort |= timeout;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
// if we had a timeout, send an abort request to the hardware,
|
||||
// so that the bus gets released
|
||||
i2cex_abort_xfer(i2c);
|
||||
}
|
||||
if (abort) break;
|
||||
|
||||
i2c->hw->data_cmd = bool_to_bit(first && i2c->restart_on_next)
|
||||
<< I2C_IC_DATA_CMD_RESTART_LSB |
|
||||
bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
|
||||
I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read
|
||||
|
||||
do {
|
||||
abort_reason = i2c->hw->tx_abrt_source;
|
||||
abort = (bool)i2c->hw->clr_tx_abrt;
|
||||
|
||||
if (timeout_check) {
|
||||
timeout = timeout_check(ts);
|
||||
abort |= timeout;
|
||||
}
|
||||
tight_loop_contents(); // ?
|
||||
} while (!abort && !i2c_get_read_available(i2c));
|
||||
|
||||
if (timeout) {
|
||||
// if we had a timeout, send an abort request to the hardware,
|
||||
// so that the bus gets released
|
||||
i2cex_abort_xfer(i2c);
|
||||
}
|
||||
if (abort) break;
|
||||
|
||||
uint8_t v = (uint8_t)i2c->hw->data_cmd;
|
||||
// printf("\ngot read %02x\n", v);
|
||||
*dst++ = v;
|
||||
}
|
||||
|
||||
int rval;
|
||||
|
||||
if (abort) {
|
||||
// printf("\ngot abrt: ");
|
||||
const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS |
|
||||
I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS |
|
||||
I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS;
|
||||
|
||||
if (timeout) { /*printf("timeout\n");*/
|
||||
rval = PICO_ERROR_TIMEOUT;
|
||||
} else if (!abort_reason || (abort_reason & addr_noack)) { // printf("disconn\n");
|
||||
rval = PICO_ERROR_GENERIC;
|
||||
} else { /*printf("unk\n");*/
|
||||
rval = PICO_ERROR_GENERIC;
|
||||
}
|
||||
} else
|
||||
rval = byte_ctr;
|
||||
|
||||
i2c->restart_on_next = nostop;
|
||||
return rval;
|
||||
}
|
||||
static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit,
|
||||
const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) {
|
||||
absolute_time_t t = make_timeout_time_us(timeout_us);
|
||||
return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t);
|
||||
}
|
||||
static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, uint8_t* dst,
|
||||
size_t len, bool nostop, uint32_t timeout_us) {
|
||||
absolute_time_t t = make_timeout_time_us(timeout_us);
|
||||
return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t);
|
||||
}
|
||||
|
||||
__attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void) {
|
||||
// TODO: SMBUS_EMUL_ALL => I2C_M_RECV_LEN
|
||||
// TODO: maybe also PROTOCOL_MANGLING, NOSTART
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
void i2ctu_dev_init(void) {
|
||||
// default to 100 kHz (SDK example default so should be ok)
|
||||
delay = 10;
|
||||
delay2 = 5;
|
||||
i2c_init(PINOUT_I2C_DEV, 100 * 1000);
|
||||
|
||||
gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C);
|
||||
gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(PINOUT_I2C_SCL);
|
||||
gpio_pull_up(PINOUT_I2C_SDA);
|
||||
|
||||
bi_decl(bi_2pins_with_func(PINOUT_I2C_SCL, PINOUT_I2C_SDA, GPIO_FUNC_I2C));
|
||||
}
|
||||
void i2ctu_dev_deinit(void) {
|
||||
gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_NULL);
|
||||
gpio_disable_pulls(PINOUT_I2C_SCL);
|
||||
gpio_disable_pulls(PINOUT_I2C_SDA);
|
||||
|
||||
// default to 100 kHz (SDK example default so should be ok)
|
||||
delay = 10;
|
||||
delay2 = 5;
|
||||
i2c_deinit(PINOUT_I2C_DEV);
|
||||
}
|
||||
|
||||
uint32_t i2ctu_dev_set_freq(uint32_t freq, uint32_t us) {
|
||||
delay = us;
|
||||
delay2 = us >> 1;
|
||||
if (!delay2) delay2 = 1;
|
||||
|
||||
return i2c_set_baudrate(PINOUT_I2C_DEV, freq);
|
||||
}
|
||||
|
||||
enum itu_status i2ctu_dev_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr,
|
||||
const uint8_t* buf, size_t len) {
|
||||
bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END);
|
||||
bool bit10 = flags & I2C_M_TEN;
|
||||
|
||||
/*if (len == 0) {
|
||||
// do a read, that's less hazardous
|
||||
uint8_t stuff = 0;
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, &stuff, 1,
|
||||
nostop, 1000*1000);
|
||||
if (rv < 0) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
} else*/
|
||||
{
|
||||
int rv = i2cex_write_timeout_us(PINOUT_I2C_DEV, addr, bit10, buf, len, nostop, 1000 * 1000);
|
||||
if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
}
|
||||
}
|
||||
enum itu_status i2ctu_dev_read(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr,
|
||||
uint8_t* buf, size_t len) {
|
||||
bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END);
|
||||
bool bit10 = flags & I2C_M_TEN;
|
||||
|
||||
/*if (len == 0) {
|
||||
uint8_t stuff = 0;
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, &stuff, 1,
|
||||
nostop, 1000*1000);
|
||||
if (rv < 0) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
} else*/
|
||||
{
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, buf, len, nostop, 1000 * 1000);
|
||||
// printf("p le rv=%d buf=%02x ", rv, buf[0]);
|
||||
if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef PINOUT_H_
|
||||
#define PINOUT_H_
|
||||
|
||||
// UART config
|
||||
#define PINOUT_UART_TX 4
|
||||
#define PINOUT_UART_RX 5
|
||||
#define PINOUT_UART_CTS 10
|
||||
#define PINOUT_UART_RTS 11
|
||||
#define PINOUT_UART_INTERFACE uart1
|
||||
#define PINOUT_UART_BAUDRATE 115200
|
||||
|
||||
// JTAG config
|
||||
#define PINOUT_JTAG_TCK 2 // == SWCLK
|
||||
#define PINOUT_JTAG_TMS 3 // == SWDIO
|
||||
#define PINOUT_JTAG_TDI 6
|
||||
#define PINOUT_JTAG_TDO 7
|
||||
#define PINOUT_JTAG_nTRST 8
|
||||
#define PINOUT_JTAG_nRESET 9
|
||||
|
||||
// SPI config
|
||||
#define PINOUT_SPI_DEV spi1
|
||||
#define PINOUT_SPI_SCLK 14
|
||||
#define PINOUT_SPI_MOSI 15
|
||||
#define PINOUT_SPI_MISO 12
|
||||
#define PINOUT_SPI_nCS 13
|
||||
|
||||
// I2C config
|
||||
#define PINOUT_I2C_DEV i2c0
|
||||
#define PINOUT_I2C_SCL 21
|
||||
#define PINOUT_I2C_SDA 20
|
||||
|
||||
// LED config
|
||||
|
||||
// you can change these two as you like
|
||||
#define PINOUT_LED_CONNECTED 1
|
||||
#define PINOUT_LED_RUNNING 0
|
||||
|
||||
#ifndef PINOUT_LED
|
||||
#ifndef PICO_DEFAULT_LED_PIN
|
||||
#error "PICO_DEFAULT_LED_PIN is not defined, run PICOPROBE_LED=<led_pin> cmake"
|
||||
#elif PICO_DEFAULT_LED_PIN == -1
|
||||
#error "PICO_DEFAULT_LED_PIN is defined as -1, run PICOPROBE_LED=<led_pin> cmake"
|
||||
#else
|
||||
#define PINOUT_LED PICO_DEFAULT_LED_PIN
|
||||
#endif
|
||||
#endif /* PICOPROBE_LED */
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hardware/spi.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
#include "m_default/pinout.h"
|
||||
|
||||
#include "m_default/serprog.h"
|
||||
|
||||
static bool cs_asserted;
|
||||
|
||||
void sp_spi_init(void) {
|
||||
cs_asserted = false;
|
||||
|
||||
spi_init(PINOUT_SPI_DEV, 512 * 1000); // default to 512 kHz
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PINOUT_SPI_SCLK, GPIO_FUNC_SPI);
|
||||
|
||||
// gpio_set_function(PINOUT_SPI_nCS, GPIO_FUNC_SIO);
|
||||
gpio_init(PINOUT_SPI_nCS);
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
gpio_set_dir(PINOUT_SPI_nCS, GPIO_OUT);
|
||||
|
||||
bi_decl(bi_3pins_with_func(PINOUT_SPI_MISO, PINOUT_SPI_MOSI, PINOUT_SPI_SCLK, GPIO_FUNC_SPI));
|
||||
bi_decl(bi_1pin_with_name(PINOUT_SPI_nCS, "SPI #CS"));
|
||||
}
|
||||
void sp_spi_deinit(void) {
|
||||
cs_asserted = false;
|
||||
|
||||
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_SPI_SCLK, GPIO_FUNC_NULL);
|
||||
gpio_set_function(PINOUT_SPI_nCS , GPIO_FUNC_NULL);
|
||||
|
||||
gpio_set_dir(PINOUT_SPI_nCS, GPIO_IN);
|
||||
gpio_disable_pulls(PINOUT_SPI_nCS);
|
||||
|
||||
spi_deinit(PINOUT_SPI_DEV);
|
||||
}
|
||||
uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) {
|
||||
return spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted);
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_cs_deselect)(void) {
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = false;
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_cs_select)(void) {
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
cs_asserted = true;
|
||||
}
|
||||
|
||||
void __not_in_flash_func(sp_spi_op_begin)(void) {
|
||||
// sp_spi_cs_select();
|
||||
if (!cs_asserted) {
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 0);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
}
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_end)(void) {
|
||||
// sp_spi_cs_deselect();
|
||||
if (!cs_asserted) { // YES, this condition is the intended one!
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
gpio_put(PINOUT_SPI_nCS, 1);
|
||||
asm volatile("nop\nnop\nnop"); // idk if this is needed
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use dma?
|
||||
void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const uint8_t* write_data) {
|
||||
spi_write_blocking(PINOUT_SPI_DEV, write_data, write_len);
|
||||
}
|
||||
void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, uint8_t* read_data) {
|
||||
spi_read_blocking(PINOUT_SPI_DEV, 0, read_data, read_len);
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// vim: set et:
|
||||
|
||||
#include "m_default/tempsensor.h"
|
||||
|
||||
#include <hardware/adc.h>
|
||||
#include <hardware/resets.h>
|
||||
|
||||
#define T_SLOPE (-0.001721f)
|
||||
#define T_BIAS (0.706f)
|
||||
#define V_MAX (3.3f)
|
||||
#define D_RANGE (4096)
|
||||
#define T_OFF (27)
|
||||
|
||||
// convert float to x.4 fixed format
|
||||
#define float2fix(x) (int)((x) * (1 << 4))
|
||||
|
||||
// convert x.4 fixed to 8.4 fixed
|
||||
__attribute__((__const__)) inline static int16_t trunc_8fix4(int fix) {
|
||||
// clang-format off
|
||||
if (fix > 4095) fix = 4095;
|
||||
if (fix < -4096) fix = -4096;
|
||||
// clang-format on
|
||||
return fix;
|
||||
}
|
||||
|
||||
void tempsense_dev_init(void) {
|
||||
adc_init();
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
}
|
||||
void tempsense_dev_deinit(void) {
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
// call init, as it resets the ADC control register
|
||||
adc_init();
|
||||
// we still need to disable it again afterwards, though
|
||||
reset_block(RESETS_RESET_ADC_BITS);
|
||||
}
|
||||
// 8.4
|
||||
int16_t tempsense_dev_get_temp(void) {
|
||||
adc_select_input(4); // select temp sensor
|
||||
uint16_t result = adc_read();
|
||||
|
||||
float voltage = result * (V_MAX / D_RANGE);
|
||||
|
||||
float tempf = T_OFF + (voltage - T_BIAS) / T_SLOPE;
|
||||
|
||||
// FIXME: use fixed point instead! but something's wrong with the formula below
|
||||
/*int temperature = float2fix(T_OFF - T_BIAS / T_SLOPE)
|
||||
+ (int)result * float2fix(V_MAX / (D_RANGE * T_SLOPE));*/
|
||||
|
||||
return trunc_8fix4(/*temperature*/ float2fix(tempf));
|
||||
}
|
||||
|
||||
// RP2040 absolute min/max are -20/85
|
||||
// clang-format off
|
||||
int16_t tempsense_dev_get_lower(void) { return trunc_8fix4(float2fix(-15)); }
|
||||
int16_t tempsense_dev_get_upper(void) { return trunc_8fix4(float2fix( 75)); }
|
||||
int16_t tempsense_dev_get_crit (void) { return trunc_8fix4(float2fix( 80)); }
|
||||
// clang-format on
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef PROTOCFG_H_
|
||||
#define PROTOCFG_H_
|
||||
|
||||
/*#define USB_VID 0x2e8a*/ /* Raspberry Pi */
|
||||
#define USB_VID 0xcafe /* TinyUSB */
|
||||
/*#define USB_VID 0x1209*/ /* Generic */
|
||||
/*#define USB_VID 0x1d50*/ /* OpenMoko */
|
||||
#define USB_PID 0x1312
|
||||
|
||||
// TODO: other RP2040 boards
|
||||
#define INFO_BOARDNAME "RP2040 Pico"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#ifndef INFO_H_
|
||||
#define INFO_H_
|
||||
|
||||
#include "bsp-info.h"
|
||||
|
||||
#define INFO_MANUFACTURER "BLAHAJ CTF"
|
||||
#define INFO_PRODUCT_BARE "Dragnbus"
|
||||
#define INFO_PRODUCT(board) "Dragnbus (" board ")"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "mode.h"
|
||||
#include "vnd_cfg.h"
|
||||
|
||||
static void enter_cb(void) {
|
||||
// TODO: init hw
|
||||
}
|
||||
static void leave_cb(void) {
|
||||
// TODO: deinit hw
|
||||
}
|
||||
|
||||
static void task_cb(void) {
|
||||
// TODO: do stuff
|
||||
}
|
||||
|
||||
static void handle_cmd_cb(uint8_t cmd) {
|
||||
uint8_t resp = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case mode_cmd_get_features:
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 1, &resp);
|
||||
break;
|
||||
default:
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
|
||||
STRID_CONFIG,
|
||||
|
||||
STRID_IF_VND_CFG,
|
||||
STRID_IF_CDC_STDIO,
|
||||
};
|
||||
enum {
|
||||
ITF_NUM_VND_CFG,
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
ITF_NUM_CDC_STDIO_COM,
|
||||
ITF_NUM_CDC_STDIO_DATA,
|
||||
//#endif
|
||||
|
||||
ITF_NUM__TOTAL
|
||||
};
|
||||
enum {
|
||||
CONFIG_TOTAL_LEN
|
||||
= TUD_CONFIG_DESC_LEN
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
+ TUD_CDC_DESC_LEN
|
||||
//#endif
|
||||
};
|
||||
|
||||
#define EPNUM_CDC_STDIO_OUT 0x03
|
||||
#define EPNUM_CDC_STDIO_IN 0x83
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x84
|
||||
|
||||
// TODO: are these ok numbers?
|
||||
#define EPNUM_VND_CFG_OUT 0x02
|
||||
#define EPNUM_VND_CFG_IN 0x82
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t desc_configuration[] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
||||
EPNUM_VND_CFG_IN, 64),
|
||||
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64,
|
||||
EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64),
|
||||
//#endif
|
||||
};
|
||||
static const char* string_desc_arr[] = {
|
||||
/*[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409)
|
||||
[STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer
|
||||
[STRID_PRODUCT] = "Dragnbus (RP2040 Pico)", // Product*/
|
||||
NULL,
|
||||
|
||||
[STRID_CONFIG] = "Configuration descriptor",
|
||||
// max string length check: |||||||||||||||||||||||||||||||
|
||||
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
|
||||
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
extern struct mode m_01_default;
|
||||
// clang-format off
|
||||
struct mode m_01_default = {
|
||||
.name = "Default mode with misc features",
|
||||
.version = 0x0010,
|
||||
.n_string_desc = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
|
||||
|
||||
.usb_desc = desc_configuration,
|
||||
.string_desc = string_desc_arr,
|
||||
|
||||
.enter = enter_cb,
|
||||
.leave = leave_cb,
|
||||
.task = task_cb,
|
||||
.handle_cmd = handle_cmd_cb,
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "mode.h"
|
||||
#include "thread.h"
|
||||
#include "vnd_cfg.h"
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
/* CMSIS-DAP */
|
||||
#include "DAP_config.h" /* ARM code *assumes* this is included prior to DAP.h */
|
||||
#include "DAP.h"
|
||||
|
||||
/* I2C-Tiny-USB */
|
||||
#include "m_default/i2ctinyusb.h"
|
||||
|
||||
/* CDC UART */
|
||||
#include "m_default/cdc.h"
|
||||
|
||||
/* CDC-Serprog */
|
||||
#include "m_default/serprog.h"
|
||||
|
||||
#ifdef DBOARD_HAS_UART
|
||||
static cothread_t uartthread;
|
||||
static uint8_t uartstack[THREAD_STACK_SIZE];
|
||||
|
||||
static void uart_thread_fn(void) {
|
||||
cdc_uart_init();
|
||||
thread_yield();
|
||||
while (1) {
|
||||
cdc_uart_task();
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
static cothread_t serprogthread;
|
||||
static uint8_t serprogstack[THREAD_STACK_SIZE];
|
||||
|
||||
static void serprog_thread_fn(void) {
|
||||
cdc_serprog_init();
|
||||
thread_yield();
|
||||
while (1) {
|
||||
cdc_serprog_task();
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void stdio_usb_set_itf_num(int itf); // TODO: move to a header!
|
||||
|
||||
static void enter_cb(void) {
|
||||
stdio_usb_set_itf_num(CDC_N_STDIO);
|
||||
|
||||
// TODO: CMSISDAP?
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
i2ctu_init();
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_UART
|
||||
uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn);
|
||||
thread_enter(uartthread); // will call cdc_uart_init() on correct thread
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn);
|
||||
thread_enter(serprogthread); // will call cdc_serprog_init() on correct thread
|
||||
#endif
|
||||
}
|
||||
static void leave_cb(void) {
|
||||
// TODO: CMSISDAP?
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
i2ctu_deinit();
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_UART
|
||||
cdc_uart_deinit();
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
cdc_serprog_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void task_cb(void) {
|
||||
#ifdef DBOARD_HAS_UART
|
||||
tud_task();
|
||||
thread_enter(uartthread);
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
tud_task();
|
||||
thread_enter(serprogthread);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_cmd_cb(uint8_t cmd) {
|
||||
uint8_t resp = 0;
|
||||
|
||||
// TODO: tempsensor control commands!
|
||||
switch (cmd) {
|
||||
case mode_cmd_get_features:
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 1, &resp);
|
||||
break;
|
||||
default:
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define TUD_I2CTINYUSB_LEN (9)
|
||||
#define TUD_I2CTINYUSB_DESCRIPTOR(_itfnum, _stridx) \
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, 0, 0, 0, _stridx \
|
||||
|
||||
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
|
||||
STRID_CONFIG,
|
||||
|
||||
STRID_IF_VND_CFG,
|
||||
STRID_IF_HID_CMSISDAP,
|
||||
STRID_IF_VND_I2CTINYUSB,
|
||||
STRID_IF_CDC_UART,
|
||||
STRID_IF_CDC_SERPROG,
|
||||
STRID_IF_CDC_STDIO,
|
||||
};
|
||||
enum {
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
ITF_NUM_VND_CFG,
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
ITF_NUM_VND_I2CTINYUSB,
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_CMSISDAP
|
||||
ITF_NUM_HID_CMSISDAP,
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_UART
|
||||
ITF_NUM_CDC_UART_COM,
|
||||
ITF_NUM_CDC_UART_DATA,
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
ITF_NUM_CDC_SERPROG_COM,
|
||||
ITF_NUM_CDC_SERPROG_DATA,
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
ITF_NUM_CDC_STDIO_COM,
|
||||
ITF_NUM_CDC_STDIO_DATA,
|
||||
#endif
|
||||
|
||||
ITF_NUM__TOTAL
|
||||
};
|
||||
enum {
|
||||
CONFIG_TOTAL_LEN
|
||||
= TUD_CONFIG_DESC_LEN
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
+ TUD_I2CTINYUSB_LEN
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_CMSISDAP
|
||||
+ TUD_HID_INOUT_DESC_LEN
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_UART
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
};
|
||||
|
||||
#define EPNUM_VND_CFG_OUT 0x01
|
||||
#define EPNUM_VND_CFG_IN 0x81
|
||||
#define EPNUM_HID_CMSISDAP 0x02
|
||||
#define EPNUM_CDC_UART_OUT 0x03
|
||||
#define EPNUM_CDC_UART_IN 0x83
|
||||
#define EPNUM_CDC_UART_NOTIF 0x84
|
||||
#define EPNUM_CDC_SERPROG_OUT 0x05
|
||||
#define EPNUM_CDC_SERPROG_IN 0x85
|
||||
#define EPNUM_CDC_SERPROG_NOTIF 0x86
|
||||
#define EPNUM_CDC_STDIO_OUT 0x07
|
||||
#define EPNUM_CDC_STDIO_IN 0x87
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x88
|
||||
|
||||
/*#define EPNUM_CDC_UART_OUT 0x02
|
||||
#define EPNUM_CDC_UART_IN 0x82
|
||||
#define EPNUM_CDC_UART_NOTIF 0x83
|
||||
#define EPNUM_HID_CMSISDAP 0x04
|
||||
#define EPNUM_CDC_SERPROG_OUT 0x05
|
||||
#define EPNUM_CDC_SERPROG_IN 0x85
|
||||
#define EPNUM_CDC_SERPROG_NOTIF 0x86
|
||||
#define EPNUM_CDC_STDIO_OUT 0x07
|
||||
#define EPNUM_CDC_STDIO_IN 0x87
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x88*/
|
||||
|
||||
// clang-format off
|
||||
#if CFG_TUD_HID > 0
|
||||
static const uint8_t desc_hid_report[] = { // ugh
|
||||
TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE)
|
||||
};
|
||||
#endif
|
||||
// TODO: replace magic 64s by actual buffer size macros
|
||||
static const uint8_t desc_configuration[] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
||||
EPNUM_VND_CFG_IN, 64),
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
TUD_I2CTINYUSB_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, STRID_IF_VND_I2CTINYUSB),
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_CMSISDAP
|
||||
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, STRID_IF_HID_CMSISDAP,
|
||||
0 /*HID_PROTOCOL_NONE*/, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP,
|
||||
0x80 | (EPNUM_HID_CMSISDAP + 0), CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_UART
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, STRID_IF_CDC_UART, EPNUM_CDC_UART_NOTIF, 64,
|
||||
EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64),
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, STRID_IF_CDC_SERPROG, EPNUM_CDC_SERPROG_NOTIF,
|
||||
64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64),
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64,
|
||||
EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64),
|
||||
#endif
|
||||
};
|
||||
static const char* string_desc_arr[] = {
|
||||
/*[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409)
|
||||
[STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer
|
||||
[STRID_PRODUCT] = "Dragnbus (RP2040 Pico)", // Product*/
|
||||
NULL,
|
||||
|
||||
[STRID_CONFIG] = "Configuration descriptor",
|
||||
// max string length check: |||||||||||||||||||||||||||||||
|
||||
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
|
||||
[STRID_IF_HID_CMSISDAP] = "CMSIS-DAP HID interface",
|
||||
[STRID_IF_VND_I2CTINYUSB] = "I2C-Tiny-USB interface",
|
||||
[STRID_IF_CDC_UART] = "UART CDC interface",
|
||||
[STRID_IF_CDC_SERPROG] = "Serprog CDC interface",
|
||||
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#ifdef DBOARD_HAS_CMSISDAP
|
||||
static const uint8_t* my_hid_descriptor_report_cb(uint8_t instance) {
|
||||
(void)instance;
|
||||
|
||||
return desc_hid_report;
|
||||
}
|
||||
/*static uint16_t my_hid_get_report_cb(uint8_t instance, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||
// TODO not implemented
|
||||
(void)instance;
|
||||
(void)report_id;
|
||||
(void)report_type;
|
||||
(void)buffer;
|
||||
(void)reqlen;
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
static void my_hid_set_report_cb(uint8_t instance, uint8_t report_id,
|
||||
hid_report_type_t report_type, uint8_t const* rx_buffer, uint16_t bufsize) {
|
||||
static uint8_t tx_buffer[CFG_TUD_HID_EP_BUFSIZE];
|
||||
uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize);
|
||||
|
||||
(void)instance;
|
||||
(void)report_id;
|
||||
(void)report_type;
|
||||
|
||||
DAP_ProcessCommand(rx_buffer, tx_buffer);
|
||||
|
||||
tud_hid_report(0, tx_buffer, response_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_I2CTINYUSB
|
||||
static bool my_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
||||
tusb_control_request_t const* req) {
|
||||
return i2ctu_ctl_req(rhport, ep_addr, req);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern struct mode m_01_default;
|
||||
// clang-format off
|
||||
struct mode m_01_default = {
|
||||
.name = "Default mode with misc features",
|
||||
.version = 0x0010,
|
||||
.n_string_desc = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
|
||||
|
||||
.usb_desc = desc_configuration,
|
||||
.string_desc = string_desc_arr,
|
||||
|
||||
.enter = enter_cb,
|
||||
.leave = leave_cb,
|
||||
.task = task_cb,
|
||||
.handle_cmd = handle_cmd_cb,
|
||||
|
||||
#if defined(DBOARD_HAS_CMSISDAP) && CFG_TUD_HID > 0
|
||||
#if 0
|
||||
.tud_hid_get_report_cb = my_hid_get_report_cb,
|
||||
#endif
|
||||
.tud_hid_set_report_cb = my_hid_set_report_cb,
|
||||
.tud_hid_descriptor_report_cb = my_hid_descriptor_report_cb,
|
||||
#endif
|
||||
|
||||
#if defined(DBOARD_HAS_I2CTINYUSB)
|
||||
.tud_vendor_control_xfer_cb = i2ctu_ctl_req,
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
#ifndef CDC_H_
|
||||
#define CDC_H_
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
/* BSP function prototypes for various USB-CDC interfaces */
|
||||
#ifdef DBOARD_HAS_UART
|
||||
void cdc_uart_init(void);
|
||||
void cdc_uart_deinit(void);
|
||||
void cdc_uart_task(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
|
||||
#include "info.h"
|
||||
#include "util.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "serprog.h"
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t serprog_cmdmap[32] = {
|
||||
0x3f, // cmd 00..05 not 0x06 (Q_CHIPSIZE) and 0x07 (Q_OPBUF), as this is a SPI-only device
|
||||
0x01, // only cmd 08
|
||||
0x1f, // cmd 10..15 supported
|
||||
0, // rest is 0
|
||||
};
|
||||
// clang-format on
|
||||
static const char serprog_pgmname[16] = INFO_PRODUCT_BARE;
|
||||
|
||||
static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||
static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE];
|
||||
|
||||
static uint32_t rxavail, rxpos;
|
||||
|
||||
void cdc_serprog_init(void) {
|
||||
rxavail = 0;
|
||||
rxpos = 0;
|
||||
|
||||
sp_spi_init();
|
||||
}
|
||||
void cdc_serprog_deinit(void) {
|
||||
sp_spi_deinit();
|
||||
|
||||
rxavail = 0;
|
||||
rxpos = 0;
|
||||
}
|
||||
|
||||
static uint8_t read_byte(void) {
|
||||
while (rxavail <= 0) {
|
||||
if (!tud_cdc_n_connected(CDC_N_SERPROG) || !tud_cdc_n_available(CDC_N_SERPROG)) {
|
||||
thread_yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
rxpos = 0;
|
||||
rxavail = tud_cdc_n_read(CDC_N_SERPROG, rx_buf, sizeof rx_buf);
|
||||
|
||||
if (rxavail == 0) thread_yield();
|
||||
}
|
||||
|
||||
uint8_t rv = rx_buf[rxpos];
|
||||
++rxpos;
|
||||
--rxavail;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void handle_cmd(void) {
|
||||
uint32_t nresp = 0;
|
||||
|
||||
uint8_t cmd = read_byte();
|
||||
switch (cmd) {
|
||||
case S_CMD_NOP:
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
break;
|
||||
case S_CMD_SYNCNOP:
|
||||
tx_buf[0] = S_NAK;
|
||||
tx_buf[1] = S_ACK;
|
||||
nresp = 2;
|
||||
break;
|
||||
case S_CMD_Q_IFACE:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = SERPROG_IFACE_VERSION & 0xff;
|
||||
tx_buf[2] = (SERPROG_IFACE_VERSION >> 8) & 0xff;
|
||||
nresp = 3;
|
||||
break;
|
||||
case S_CMD_Q_CMDMAP:
|
||||
tx_buf[0] = S_ACK;
|
||||
memcpy(&tx_buf[1], serprog_cmdmap, sizeof serprog_cmdmap);
|
||||
nresp = sizeof(serprog_cmdmap) + 1;
|
||||
break;
|
||||
case S_CMD_Q_PGMNAME:
|
||||
tx_buf[0] = S_ACK;
|
||||
memcpy(&tx_buf[1], serprog_pgmname, sizeof serprog_pgmname);
|
||||
nresp = sizeof(serprog_pgmname) + 1;
|
||||
break;
|
||||
case S_CMD_Q_SERBUF:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = sizeof(rx_buf) & 0xff;
|
||||
tx_buf[2] = (sizeof(rx_buf) >> 8) & 0xff;
|
||||
nresp = 3;
|
||||
break;
|
||||
case S_CMD_Q_BUSTYPE:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = 1 << 3; // SPI only
|
||||
nresp = 2;
|
||||
break;
|
||||
case S_CMD_Q_WRNMAXLEN:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = (sizeof(tx_buf) - 1) & 0xff;
|
||||
tx_buf[2] = ((sizeof(tx_buf) - 1) >> 8) & 0xff;
|
||||
tx_buf[3] = ((sizeof(tx_buf) - 1) >> 16) & 0xff;
|
||||
nresp = 4;
|
||||
break;
|
||||
case S_CMD_Q_RDNMAXLEN:
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = (sizeof(rx_buf) - 1) & 0xff;
|
||||
tx_buf[2] = ((sizeof(rx_buf) - 1) >> 8) & 0xff;
|
||||
tx_buf[3] = ((sizeof(rx_buf) - 1) >> 16) & 0xff;
|
||||
nresp = 4;
|
||||
break;
|
||||
case S_CMD_S_BUSTYPE:
|
||||
if (read_byte() /* bus type to set */ == (1 << 3)) {
|
||||
tx_buf[0] = S_ACK;
|
||||
} else {
|
||||
tx_buf[0] = S_NAK;
|
||||
}
|
||||
nresp = 1;
|
||||
break;
|
||||
|
||||
case S_CMD_SPIOP: {
|
||||
uint32_t slen, rlen;
|
||||
|
||||
// clang-format off
|
||||
slen = (uint32_t)read_byte();
|
||||
slen |= (uint32_t)read_byte() << 8;
|
||||
slen |= (uint32_t)read_byte() << 16;
|
||||
rlen = (uint32_t)read_byte();
|
||||
rlen |= (uint32_t)read_byte() << 8;
|
||||
rlen |= (uint32_t)read_byte() << 16;
|
||||
// clang-format on
|
||||
|
||||
sp_spi_op_begin();
|
||||
size_t this_batch;
|
||||
|
||||
// 1. write slen data bytes
|
||||
// we're going to use the tx buf for all operations here
|
||||
while (slen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > slen) this_batch = slen;
|
||||
|
||||
for (size_t i = 0; i < this_batch; ++i) tx_buf[i] = read_byte();
|
||||
sp_spi_op_write(this_batch, tx_buf);
|
||||
|
||||
slen -= this_batch;
|
||||
}
|
||||
|
||||
// 2. write data
|
||||
// first, do a batch of 63, because we also need to send an ACK byte
|
||||
this_batch = sizeof(tx_buf) - 1;
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
sp_spi_op_read(this_batch, &tx_buf[1]);
|
||||
tx_buf[0] = S_ACK;
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch + 1);
|
||||
rlen -= this_batch;
|
||||
|
||||
// now do in batches of 64
|
||||
while (rlen > 0) {
|
||||
this_batch = sizeof(tx_buf);
|
||||
if (this_batch > rlen) this_batch = rlen;
|
||||
|
||||
sp_spi_op_read(this_batch, tx_buf);
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch);
|
||||
|
||||
rlen -= this_batch;
|
||||
}
|
||||
tud_cdc_n_write_flush(CDC_N_SERPROG);
|
||||
|
||||
// that's it!
|
||||
sp_spi_op_end();
|
||||
nresp = 0; // we sent our own response manually
|
||||
} break;
|
||||
case S_CMD_S_SPI_FREQ: {
|
||||
uint32_t freq;
|
||||
// clang-format off
|
||||
freq = (uint32_t)read_byte();
|
||||
freq |= (uint32_t)read_byte() << 8;
|
||||
freq |= (uint32_t)read_byte() << 16;
|
||||
freq |= (uint32_t)read_byte() << 24;
|
||||
// clang-format on
|
||||
|
||||
uint32_t nfreq = sp_spi_set_freq(freq);
|
||||
|
||||
tx_buf[0] = S_ACK;
|
||||
tx_buf[1] = nfreq & 0xff;
|
||||
tx_buf[2] = (nfreq >> 8) & 0xff;
|
||||
tx_buf[3] = (nfreq >> 16) & 0xff;
|
||||
tx_buf[4] = (nfreq >> 24) & 0xff;
|
||||
nresp = 5;
|
||||
} break;
|
||||
case S_CMD_S_PINSTATE: {
|
||||
if (read_byte() == 0)
|
||||
sp_spi_cs_deselect();
|
||||
else
|
||||
sp_spi_cs_select();
|
||||
|
||||
tx_buf[0] = S_ACK;
|
||||
nresp = 1;
|
||||
} break;
|
||||
|
||||
default:
|
||||
tx_buf[0] = S_NAK;
|
||||
nresp = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nresp > 0) {
|
||||
tud_cdc_n_write(CDC_N_SERPROG, tx_buf, nresp);
|
||||
tud_cdc_n_write_flush(CDC_N_SERPROG);
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_serprog_task(void) { handle_cmd(); }
|
||||
|
||||
#endif /* DBOARD_HAS_SERPROG */
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef I2CTINYUSB_H_
|
||||
#define I2CTINYUSB_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
enum itu_command {
|
||||
ITU_CMD_ECHO = 0,
|
||||
ITU_CMD_GET_FUNC = 1,
|
||||
ITU_CMD_SET_DELAY = 2,
|
||||
ITU_CMD_GET_STATUS = 3,
|
||||
|
||||
ITU_CMD_I2C_IO_BEGIN_F = (1 << 0),
|
||||
ITU_CMD_I2C_IO_END_F = (1 << 1),
|
||||
ITU_CMD_I2C_IO_DIR_MASK = ITU_CMD_I2C_IO_BEGIN_F | ITU_CMD_I2C_IO_END_F,
|
||||
|
||||
ITU_CMD_I2C_IO = 4,
|
||||
ITU_CMD_I2C_IO_BEGIN = 4 | ITU_CMD_I2C_IO_BEGIN_F,
|
||||
ITU_CMD_I2C_IO_END = 4 | ITU_CMD_I2C_IO_END_F,
|
||||
ITU_CMD_I2C_IO_BEGINEND = 4 | ITU_CMD_I2C_IO_BEGIN_F | ITU_CMD_I2C_IO_END_F,
|
||||
};
|
||||
|
||||
enum itu_status { ITU_STATUS_IDLE = 0, ITU_STATUS_ADDR_ACK = 1, ITU_STATUS_ADDR_NAK = 2 };
|
||||
|
||||
// these two are lifted straight from the linux kernel, lmao
|
||||
enum ki2c_flags {
|
||||
I2C_M_RD = 0x0001, /* guaranteed to be 0x0001! */
|
||||
I2C_M_TEN = 0x0010, /* use only if I2C_FUNC_10BIT_ADDR */
|
||||
I2C_M_DMA_SAFE = 0x0200, /* use only in kernel space */
|
||||
I2C_M_RECV_LEN = 0x0400, /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */
|
||||
I2C_M_NO_RD_ACK = 0x0800, /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||
I2C_M_IGNORE_NAK = 0x1000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||
I2C_M_REV_DIR_ADDR = 0x2000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||
I2C_M_NOSTART = 0x4000, /* use only if I2C_FUNC_NOSTART */
|
||||
I2C_M_STOP = 0x8000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||
};
|
||||
|
||||
enum ki2c_funcs {
|
||||
I2C_FUNC_I2C = 0x00000001,
|
||||
I2C_FUNC_10BIT_ADDR = 0x00000002, /* required for I2C_M_TEN */
|
||||
I2C_FUNC_PROTOCOL_MANGLING = 0x00000004, /* required for I2C_M_IGNORE_NAK etc. */
|
||||
I2C_FUNC_SMBUS_PEC = 0x00000008,
|
||||
I2C_FUNC_NOSTART = 0x00000010, /* required for I2C_M_NOSTART */
|
||||
I2C_FUNC_SLAVE = 0x00000020,
|
||||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x00008000, /* SMBus 2.0 or later */
|
||||
I2C_FUNC_SMBUS_QUICK = 0x00010000,
|
||||
I2C_FUNC_SMBUS_READ_BYTE = 0x00020000,
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000,
|
||||
I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000,
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000,
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000,
|
||||
I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000,
|
||||
I2C_FUNC_SMBUS_PROC_CALL = 0x00800000,
|
||||
I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000, /* required for I2C_M_RECV_LEN */
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000, /* I2C-like block xfer */
|
||||
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000, /* w/ 1-byte reg. addr. */
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 = 0x10000000, /* I2C-like block xfer */
|
||||
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 = 0x20000000, /* w/ 2-byte reg. addr. */
|
||||
I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC = 0x40000000, /* SMBus 2.0 or later */
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC = 0x80000000, /* SMBus 2.0 or later */
|
||||
|
||||
I2C_FUNC_SMBUS_BYTE = (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE),
|
||||
I2C_FUNC_SMBUS_BYTE_DATA = (I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA),
|
||||
I2C_FUNC_SMBUS_WORD_DATA = (I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA),
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA = (I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA),
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK = (I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK),
|
||||
|
||||
I2C_FUNC_SMBUS_EMUL = (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_PEC),
|
||||
|
||||
/* if I2C_M_RECV_LEN is also supported */
|
||||
I2C_FUNC_SMBUS_EMUL_ALL =
|
||||
(I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL),
|
||||
};
|
||||
|
||||
__attribute__((__packed__)) struct itu_cmd {
|
||||
uint16_t flags;
|
||||
uint16_t addr;
|
||||
uint16_t len;
|
||||
uint8_t cmd;
|
||||
};
|
||||
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
/* functions to be implemented by BSP */
|
||||
__attribute__((__const__)) enum ki2c_funcs i2ctu_dev_get_func(void);
|
||||
void i2ctu_dev_init(void);
|
||||
void i2ctu_dev_deinit(void);
|
||||
uint32_t i2ctu_dev_set_freq(uint32_t freq, uint32_t us); // returns selected frequency, or 0 on error
|
||||
enum itu_status i2ctu_dev_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr,
|
||||
const uint8_t* buf, size_t len);
|
||||
enum itu_status i2ctu_dev_read(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr,
|
||||
uint8_t* buf, size_t len);
|
||||
|
||||
/* I2C-Tiny-USB protocol handling code */
|
||||
void i2ctu_init(void);
|
||||
void i2ctu_deinit(void);
|
||||
bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef SERPROG_H_
|
||||
#define SERPROG_H_
|
||||
|
||||
enum serprog_cmd {
|
||||
S_CMD_NOP = 0x00,
|
||||
S_CMD_Q_IFACE = 0x01,
|
||||
S_CMD_Q_CMDMAP = 0x02,
|
||||
S_CMD_Q_PGMNAME = 0x03,
|
||||
S_CMD_Q_SERBUF = 0x04,
|
||||
S_CMD_Q_BUSTYPE = 0x05,
|
||||
S_CMD_Q_CHIPSIZE = 0x06,
|
||||
S_CMD_Q_OPBUF = 0x07,
|
||||
S_CMD_Q_WRNMAXLEN = 0x08,
|
||||
S_CMD_R_BYTE = 0x09,
|
||||
S_CMD_R_NBYTES = 0x0a,
|
||||
S_CMD_O_INIT = 0x0b,
|
||||
S_CMD_O_WRITEB = 0x0c,
|
||||
S_CMD_O_WRITEN = 0x0d,
|
||||
S_CMD_O_DELAY = 0x0e,
|
||||
S_CMD_O_EXEC = 0x0f,
|
||||
S_CMD_SYNCNOP = 0x10,
|
||||
S_CMD_Q_RDNMAXLEN = 0x11,
|
||||
S_CMD_S_BUSTYPE = 0x12,
|
||||
S_CMD_SPIOP = 0x13,
|
||||
S_CMD_S_SPI_FREQ = 0x14,
|
||||
S_CMD_S_PINSTATE = 0x15,
|
||||
|
||||
S_CMD_MAGIC_SETTINGS = 0x53
|
||||
};
|
||||
|
||||
enum serprog_response { S_ACK = 0x06, S_NAK = 0x15 };
|
||||
|
||||
#define SERPROG_IFACE_VERSION 0x0001
|
||||
|
||||
#ifdef DBOARD_HAS_SERPROG
|
||||
/* functions to be implemented by the BSP */
|
||||
uint32_t /*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted);
|
||||
|
||||
void sp_spi_init(void);
|
||||
void sp_spi_deinit(void);
|
||||
void sp_spi_cs_deselect(void);
|
||||
void sp_spi_cs_select(void);
|
||||
void sp_spi_op_begin(void);
|
||||
void sp_spi_op_write(uint32_t write_len, const uint8_t* write_data);
|
||||
void sp_spi_op_read(uint32_t read_len, uint8_t* read_data);
|
||||
void sp_spi_op_end(void);
|
||||
|
||||
static inline void sp_spi_op_do(
|
||||
uint32_t write_len, const uint8_t* write_data, uint32_t read_len, uint8_t* read_data) {
|
||||
sp_spi_op_begin();
|
||||
sp_spi_op_write(write_len, write_data);
|
||||
sp_spi_op_write(read_len, read_data);
|
||||
sp_spi_op_end();
|
||||
}
|
||||
|
||||
/* protocol handling functions */
|
||||
void cdc_serprog_init(void);
|
||||
void cdc_serprog_deinit(void);
|
||||
void cdc_serprog_task(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef VERY_FAKE
|
||||
#include "m_default/bsp-feature.h"
|
||||
// clang-format off
|
||||
#define printf(fmt, ...) do { } while (0) \
|
||||
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
|
||||
#include "tempsensor.h"
|
||||
|
||||
static bool active;
|
||||
static uint8_t addr;
|
||||
static uint8_t reg;
|
||||
static size_t index;
|
||||
static bool instartstop, hasreg;
|
||||
|
||||
enum regid { cap = 0, config, t_upper, t_lower, t_crit, t_a, manuf_id, dev_idrev, reso };
|
||||
|
||||
#define MANUF_ID 0x0054
|
||||
#define DEV_IDREV 0x0400
|
||||
|
||||
struct {
|
||||
uint16_t config;
|
||||
uint16_t t_upper, t_lower, t_crit;
|
||||
uint8_t reso;
|
||||
} mcp9808;
|
||||
|
||||
#define float2fix(x) (int)((x) * (1 << 4))
|
||||
__attribute__((__const__)) inline static int16_t trunc_8fix4(int fix) {
|
||||
// clang-format off
|
||||
if (fix > 4095) fix = 4095;
|
||||
if (fix < -4096) fix = -4096;
|
||||
// clang-format on
|
||||
return fix;
|
||||
}
|
||||
void tempsense_init(void) {
|
||||
active = false;
|
||||
addr = 0xff;
|
||||
reg = 0;
|
||||
index = 0;
|
||||
instartstop = false;
|
||||
hasreg = false;
|
||||
|
||||
tempsense_dev_init();
|
||||
|
||||
// clang-format off
|
||||
mcp9808.t_lower = tempsense_dev_get_lower();
|
||||
mcp9808.t_upper = tempsense_dev_get_upper();
|
||||
mcp9808.t_crit = tempsense_dev_get_crit ();
|
||||
// clang-format on
|
||||
}
|
||||
void tempsense_deinit(void) {
|
||||
tempsense_dev_deinit();
|
||||
|
||||
active = false;
|
||||
addr = 0xff;
|
||||
reg = 0;
|
||||
index = 0;
|
||||
instartstop = false;
|
||||
hasreg = false;
|
||||
}
|
||||
|
||||
bool tempsense_get_active(void) { return active; }
|
||||
void tempsense_set_active(bool act) {
|
||||
active = act;
|
||||
if (!act) addr = 0xff;
|
||||
}
|
||||
uint8_t tempsense_get_addr(void) { return addr; }
|
||||
void tempsense_set_addr(uint8_t a) {
|
||||
addr = a;
|
||||
active = addr >= 0x8 && addr <= 0x77;
|
||||
printf("set: ad=%02x ac=%c\n", addr, active ? 't' : 'f');
|
||||
}
|
||||
|
||||
void tempsense_do_start(void) {
|
||||
printf("ts start\n");
|
||||
// reg = 0;
|
||||
index = 0;
|
||||
instartstop = true;
|
||||
hasreg = false;
|
||||
}
|
||||
void tempsense_do_stop(void) {
|
||||
printf("ts stop\n");
|
||||
instartstop = false;
|
||||
}
|
||||
|
||||
int tempsense_do_read(int length, uint8_t* buf) {
|
||||
printf("read l=%d reg=%02x ", length, reg);
|
||||
|
||||
if (!instartstop || length < 0) return -1; // nak
|
||||
if (length == 0) return 0; // ack
|
||||
// if (!hasreg) return -1; // nak
|
||||
|
||||
int i;
|
||||
for (i = 0; i < length; ++i, ++index) {
|
||||
switch (reg) {
|
||||
// TODO: big or little endian? seems to be big
|
||||
case cap: buf[index] = 0; break;
|
||||
case config:
|
||||
if (index == 0)
|
||||
buf[0] = (mcp9808.config >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (mcp9808.config >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case t_upper:
|
||||
if (index == 0)
|
||||
buf[0] = (mcp9808.t_upper >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (mcp9808.t_upper >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case t_lower:
|
||||
if (index == 0)
|
||||
buf[0] = (mcp9808.t_lower >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (mcp9808.t_lower >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case t_crit:
|
||||
if (index == 0)
|
||||
buf[0] = (mcp9808.t_crit >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (mcp9808.t_crit >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case t_a: {
|
||||
static uint16_t temp;
|
||||
if (index == 0) {
|
||||
int16_t res = tempsense_dev_get_temp();
|
||||
|
||||
// clang-format off
|
||||
uint32_t tup = mcp9808.t_upper & 0x1ffc;
|
||||
if (tup & 0x1000) tup |= 0xffffe000; // make negative
|
||||
uint32_t tlo = mcp9808.t_lower & 0x1ffc;
|
||||
if (tlo & 0x1000) tlo |= 0xffffe000; // make negative
|
||||
uint32_t tcr = mcp9808.t_crit & 0x1ffc;
|
||||
if (tcr & 0x1000) tcr |= 0xffffe000; // make negative
|
||||
// clang-format on
|
||||
|
||||
temp = res & 0x1fff; // data bits and sign bit
|
||||
|
||||
if ((int32_t)tlo > res) temp |= 0x2000;
|
||||
if ((int32_t)tup < res) temp |= 0x4000;
|
||||
if ((int32_t)tcr < res) temp |= 0x8000;
|
||||
|
||||
buf[0] = (temp >> 8) & 0xff;
|
||||
} else if (index == 1)
|
||||
buf[1] = (temp >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
} break;
|
||||
case manuf_id:
|
||||
if (index == 0)
|
||||
buf[0] = (MANUF_ID >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (MANUF_ID >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case dev_idrev:
|
||||
if (index == 0)
|
||||
buf[0] = (DEV_IDREV >> 8) & 0xff;
|
||||
else if (index == 1)
|
||||
buf[1] = (DEV_IDREV >> 0) & 0xff;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
case reso:
|
||||
if (index == 0)
|
||||
buf[0] = mcp9808.reso;
|
||||
else
|
||||
return index;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
int tempsense_do_write(int length, const uint8_t* buf) {
|
||||
printf("write l=%d reg=%02x iss=%c ", length, reg, instartstop ? 't' : 'f');
|
||||
|
||||
if (!instartstop || length < 0) return -1; // nak
|
||||
if (length == 0) return 0; // ack
|
||||
|
||||
if (!hasreg) {
|
||||
printf("get reg %02x ", reg);
|
||||
|
||||
reg = *buf & 0xf;
|
||||
++buf;
|
||||
--length;
|
||||
hasreg = true;
|
||||
}
|
||||
|
||||
if (length == 0) return 1; // ack, probably a read following
|
||||
|
||||
int i;
|
||||
for (i = 0; i < length; ++i, ++index) {
|
||||
switch (reg) {
|
||||
case config:
|
||||
if (index == 0) {
|
||||
mcp9808.config = (mcp9808.config & 0x00ff) | ((uint16_t)buf[0] << 8);
|
||||
} else if (index == 1) {
|
||||
mcp9808.config = (mcp9808.config & 0xff00) | ((uint16_t)buf[1] << 0);
|
||||
} else
|
||||
return index;
|
||||
break;
|
||||
case t_upper:
|
||||
if (index == 0) {
|
||||
mcp9808.t_upper = (mcp9808.t_upper & 0x00ff) | ((uint16_t)buf[0] << 8);
|
||||
} else if (index == 1) {
|
||||
mcp9808.t_upper = (mcp9808.t_upper & 0xff00) | ((uint16_t)buf[1] << 0);
|
||||
} else
|
||||
return index;
|
||||
break;
|
||||
case t_lower:
|
||||
if (index == 0) {
|
||||
mcp9808.t_lower = (mcp9808.t_lower & 0x00ff) | ((uint16_t)buf[0] << 8);
|
||||
} else if (index == 1) {
|
||||
mcp9808.t_lower = (mcp9808.t_lower & 0xff00) | ((uint16_t)buf[1] << 0);
|
||||
} else
|
||||
return index;
|
||||
break;
|
||||
case t_crit:
|
||||
if (index == 0) {
|
||||
mcp9808.t_crit = (mcp9808.t_crit & 0x00ff) | ((uint16_t)buf[0] << 8);
|
||||
} else if (index == 1) {
|
||||
mcp9808.t_crit = (mcp9808.t_crit & 0xff00) | ((uint16_t)buf[1] << 0);
|
||||
} else
|
||||
return index;
|
||||
break;
|
||||
case reso: mcp9808.reso = buf[index]; break;
|
||||
default: printf("unk reg\n"); return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// vim: set et:
|
||||
|
||||
#ifndef TEMPSENSOR_H_
|
||||
#define TEMPSENSOR_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void tempsense_init(void);
|
||||
void tempsense_deinit(void);
|
||||
|
||||
bool tempsense_get_active(void);
|
||||
void tempsense_set_active(bool active);
|
||||
uint8_t tempsense_get_addr(void);
|
||||
void tempsense_set_addr(uint8_t addr);
|
||||
|
||||
void tempsense_do_start(void); // start cond
|
||||
int tempsense_do_read(int length, uint8_t* buf);
|
||||
int tempsense_do_write(int length, const uint8_t* buf);
|
||||
void tempsense_do_stop(void); // stop cond
|
||||
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
void tempsense_dev_init(void);
|
||||
void tempsense_dev_deinit(void);
|
||||
// 8.4
|
||||
int16_t tempsense_dev_get_temp(void);
|
||||
|
||||
int16_t tempsense_dev_get_lower(void);
|
||||
int16_t tempsense_dev_get_upper(void);
|
||||
int16_t tempsense_dev_get_crit(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
|
||||
// clang-format off
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hardware/i2c.h>
|
||||
|
||||
#include <tusb.h>
|
||||
#include <device/usbd_pvt.h>
|
||||
|
||||
#include "m_default/bsp-feature.h"
|
||||
|
||||
#include "i2ctinyusb.h"
|
||||
|
||||
#include "tempsensor.h"
|
||||
// clang-format on
|
||||
|
||||
static enum itu_status status;
|
||||
static struct itu_cmd curcmd;
|
||||
|
||||
static uint8_t rxbuf[128];
|
||||
static uint8_t txbuf[128];
|
||||
|
||||
void i2ctu_init(void) {
|
||||
status = ITU_STATUS_IDLE;
|
||||
memset(&curcmd, 0, sizeof curcmd);
|
||||
|
||||
i2ctu_dev_init();
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
tempsense_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void i2ctu_deinit(void) {
|
||||
status = ITU_STATUS_IDLE;
|
||||
memset(&curcmd, 0, sizeof curcmd);
|
||||
|
||||
i2ctu_dev_deinit();
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
tempsense_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool i2ctu_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) {
|
||||
(void)rhport;
|
||||
|
||||
/*static char* stages[]={"SETUP","DATA","ACK"};
|
||||
static char* types[]={"STD","CLS","VND","INV"};
|
||||
|
||||
printf("ctl req stage=%s rt=%s, wIndex=%04x, bReq=%02x, wValue=%04x wLength=%04x\n",
|
||||
stages[stage], types[req->bmRequestType_bit.type],
|
||||
req->wIndex, req->bRequest, req->wValue, req->wLength);*/
|
||||
|
||||
if (req->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) return true;
|
||||
|
||||
if (stage == CONTROL_STAGE_DATA) {
|
||||
struct itu_cmd cmd = curcmd;
|
||||
|
||||
if (req->bRequest >= ITU_CMD_I2C_IO && req->bRequest <= ITU_CMD_I2C_IO_BEGINEND &&
|
||||
cmd.cmd == req->bRequest && cmd.flags == req->wValue && cmd.addr == req->wIndex &&
|
||||
cmd.len == req->wLength) {
|
||||
// printf("WDATA a=%04hx l=%04hx ", cmd.addr, cmd.len);
|
||||
|
||||
// printf("data=%02x %02x...\n", rxbuf[0], rxbuf[1]);
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
|
||||
// FIXME: fix status handling
|
||||
int rv = tempsense_do_write(cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len, rxbuf);
|
||||
if (rv < 0 || rv != cmd.len)
|
||||
status = ITU_STATUS_ADDR_NAK;
|
||||
else
|
||||
status = ITU_STATUS_ADDR_ACK;
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
status = i2ctu_dev_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, rxbuf,
|
||||
cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
|
||||
}
|
||||
|
||||
// cancel curcmd
|
||||
curcmd.cmd = 0xff;
|
||||
}
|
||||
return true;
|
||||
} else if (stage == CONTROL_STAGE_SETUP) {
|
||||
switch (req->bRequest) {
|
||||
case ITU_CMD_ECHO: { // flags to be echoed back, addr unused, len=2
|
||||
|
||||
if (req->wLength != 2) return false; // bad length -> let's stall
|
||||
|
||||
uint8_t rv[2];
|
||||
rv[0] = req->wValue & 0xff;
|
||||
rv[1] = (req->wValue >> 8) & 0xff;
|
||||
return tud_control_xfer(rhport, req, rv, sizeof rv);
|
||||
} break;
|
||||
case ITU_CMD_GET_FUNC: { // flags unused, addr unused, len=4
|
||||
if (req->wLength != 4) return false;
|
||||
|
||||
const uint32_t func = i2ctu_dev_get_func();
|
||||
txbuf[0] = func & 0xff;
|
||||
txbuf[1] = (func >> 8) & 0xff;
|
||||
txbuf[2] = (func >> 16) & 0xff;
|
||||
txbuf[3] = (func >> 24) & 0xff;
|
||||
return tud_control_xfer(rhport, req, txbuf, 4);
|
||||
} break;
|
||||
case ITU_CMD_SET_DELAY: { // flags=delay, addr unused, len=0
|
||||
if (req->wLength != 0) return false;
|
||||
|
||||
uint32_t us = req->wValue ? req->wValue : 1;
|
||||
uint32_t freq = 1000 * 1000 / us;
|
||||
|
||||
// printf("set freq us=%u freq=%u\n", us, freq);
|
||||
if (i2ctu_dev_set_freq(freq, us) != 0) // returned an ok frequency
|
||||
return tud_control_status(rhport, req);
|
||||
else
|
||||
return false;
|
||||
} break;
|
||||
case ITU_CMD_GET_STATUS: { // flags unused, addr unused, len=1
|
||||
if (req->wLength != 1) return false;
|
||||
|
||||
uint8_t rv = status;
|
||||
return tud_control_xfer(rhport, req, &rv, 1);
|
||||
} break;
|
||||
|
||||
case ITU_CMD_I2C_IO: // flags: ki2c_flags
|
||||
case ITU_CMD_I2C_IO_BEGIN: // addr: I2C address
|
||||
case ITU_CMD_I2C_IO_END: // len: transfer size
|
||||
case ITU_CMD_I2C_IO_BEGINEND: { // (transfer dir is in flags)
|
||||
struct itu_cmd cmd;
|
||||
cmd.flags = req->wValue;
|
||||
cmd.addr = req->wIndex;
|
||||
cmd.len = req->wLength;
|
||||
cmd.cmd = req->bRequest;
|
||||
|
||||
if (cmd.flags & I2C_M_RD) { // read from I2C device
|
||||
// printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len);
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
|
||||
int rv = tempsense_do_read(
|
||||
cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len, txbuf);
|
||||
if (rv < 0 || rv != cmd.len)
|
||||
status = ITU_STATUS_ADDR_NAK;
|
||||
else
|
||||
status = ITU_STATUS_ADDR_ACK;
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
status = i2ctu_dev_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr,
|
||||
txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len);
|
||||
}
|
||||
// printf("data=%02x %02x...\n", txbuf[0], txbuf[1]);
|
||||
return tud_control_xfer(
|
||||
rhport, req, txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len);
|
||||
} else { // write
|
||||
// printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len);
|
||||
if (cmd.len == 0) { // address probe -> do this here
|
||||
uint8_t bleh = 0;
|
||||
#ifdef DBOARD_HAS_TEMPSENSOR
|
||||
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
|
||||
int rv = tempsense_do_write(0, &bleh);
|
||||
if (rv < 0 || rv != cmd.len)
|
||||
status = ITU_STATUS_ADDR_NAK;
|
||||
else
|
||||
status = ITU_STATUS_ADDR_ACK;
|
||||
if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
status = i2ctu_dev_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
cmd.addr, &bleh, 0);
|
||||
}
|
||||
// printf("probe -> %d\n", status);
|
||||
return tud_control_status(rhport, req);
|
||||
} else {
|
||||
// handled in DATA stage!
|
||||
curcmd = cmd;
|
||||
bool rv = tud_control_xfer(rhport, req, rxbuf,
|
||||
cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
// printf("I2C-Tiny-USB: unknown command %02x\n", req->bRequest);
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
return true; // other stage...
|
||||
}
|
||||
|
||||
#endif /* DBOARD_HAS_I2C */
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <tusb.h>
|
||||
|
||||
#include "mode.h"
|
||||
#include "vnd_cfg.h"
|
||||
|
||||
static void enter_cb(void) {
|
||||
// TODO: init hw
|
||||
}
|
||||
static void leave_cb(void) {
|
||||
// TODO: deinit hw
|
||||
}
|
||||
|
||||
static void task_cb(void) {
|
||||
// TODO: do stuff
|
||||
}
|
||||
|
||||
static void handle_cmd_cb(uint8_t cmd) {
|
||||
uint8_t resp = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case mode_cmd_get_features:
|
||||
resp = 0x42;
|
||||
vnd_cfg_write_resp(cfg_resp_ok, 1, &resp);
|
||||
break;
|
||||
default:
|
||||
vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
STRID_LANGID = 0,
|
||||
STRID_MANUFACTURER,
|
||||
STRID_PRODUCT,
|
||||
STRID_SERIAL,
|
||||
|
||||
STRID_CONFIG,
|
||||
|
||||
STRID_IF_VND_CFG,
|
||||
STRID_IF_CDC_STDIO,
|
||||
};
|
||||
enum {
|
||||
ITF_NUM_VND_CFG,
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
ITF_NUM_CDC_STDIO_COM,
|
||||
ITF_NUM_CDC_STDIO_DATA,
|
||||
//#endif
|
||||
|
||||
ITF_NUM__TOTAL
|
||||
};
|
||||
enum {
|
||||
CONFIG_TOTAL_LEN
|
||||
= TUD_CONFIG_DESC_LEN
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
+ TUD_CDC_DESC_LEN
|
||||
//#endif
|
||||
};
|
||||
|
||||
#define EPNUM_CDC_STDIO_OUT 0x03
|
||||
#define EPNUM_CDC_STDIO_IN 0x83
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x84
|
||||
|
||||
// TODO: are these ok numbers?
|
||||
#define EPNUM_VND_CFG_OUT 0x02
|
||||
#define EPNUM_VND_CFG_IN 0x82
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t desc_configuration[] = {
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
||||
EPNUM_VND_CFG_IN, 64),
|
||||
|
||||
//#ifdef USE_USBCDC_FOR_STDIO
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64,
|
||||
EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64),
|
||||
//#endif
|
||||
};
|
||||
static const char* string_desc_arr[] = {
|
||||
/*[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409)
|
||||
[STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer
|
||||
[STRID_PRODUCT] = "Dragnbus (hi mum)", // Product*/
|
||||
|
||||
NULL,
|
||||
[STRID_CONFIG] = "Configuration descriptor",
|
||||
// max string length check: |||||||||||||||||||||||||||||||
|
||||
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
|
||||
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
extern struct mode m_02_default2;
|
||||
// clang-format off
|
||||
struct mode m_02_default2 = {
|
||||
.name = "Default mode but betterer!",
|
||||
.version = 0x0020,
|
||||
.n_string_desc = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
|
||||
|
||||
.usb_desc = desc_configuration,
|
||||
.string_desc = string_desc_arr,
|
||||
|
||||
.enter = enter_cb,
|
||||
.leave = leave_cb,
|
||||
.task = task_cb,
|
||||
.handle_cmd = handle_cmd_cb,
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -13,8 +13,10 @@
|
|||
static cothread_t vndcfg_thread;
|
||||
static uint8_t vndcfg_stack[THREAD_STACK_SIZE];
|
||||
|
||||
// FIXME: move declaration elsewhere
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
void stdio_usb_init(void);
|
||||
void stdio_usb_set_itf_num(int itf);
|
||||
#endif
|
||||
|
||||
static void vndcfg_thread_fn(void) {
|
||||
|
@ -32,7 +34,7 @@ int main() {
|
|||
board_init(); // tinyusb hardware support function
|
||||
|
||||
vndcfg_thread = co_derive(vndcfg_stack, sizeof vndcfg_stack, vndcfg_thread_fn);
|
||||
co_switch(vndcfg_thread);
|
||||
thread_enter(vndcfg_thread);
|
||||
|
||||
modes_init();
|
||||
if (mode_current) mode_current->enter();
|
||||
|
@ -41,6 +43,8 @@ int main() {
|
|||
|
||||
// FIXME: put elsewhere?
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
stdio_usb_set_itf_num(0);
|
||||
|
||||
stdio_usb_init();
|
||||
#endif
|
||||
|
||||
|
@ -49,7 +53,7 @@ int main() {
|
|||
if (mode_current) mode_current->task();
|
||||
|
||||
tud_task();
|
||||
co_switch(vndcfg_thread);
|
||||
thread_enter(vndcfg_thread);
|
||||
|
||||
// do this here instead of in a callback or in the vnd_cfg_task fn
|
||||
if (mode_next_id != -1) {
|
||||
|
|
|
@ -34,10 +34,10 @@ struct mode {
|
|||
#if CFG_TUD_CDC > 0
|
||||
void (*tud_cdc_line_coding_cb)(uint8_t itf, cdc_line_coding_t const* line_coding);
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t ep_addr,
|
||||
tusb_control_request_t const* req);
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
uint8_t const* (*tud_hid_descriptor_report_cb)(uint8_t instance);
|
||||
uint8_t const* (*tud_descriptor_device_cb)(void);
|
||||
|
@ -70,10 +70,10 @@ void mode_std_hid_set_report_cb(uint8_t instance, uint8_t report_id,
|
|||
#if CFG_TUD_CDC > 0
|
||||
void mode_std_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding);
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
bool mode_std_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
||||
tusb_control_request_t const* req);
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
#include "mode.h"
|
||||
|
||||
extern struct mode m_01_default, m_02_default2;
|
||||
extern struct mode m_01_default/*, m_02_default2*/;
|
||||
|
||||
// clang-format off
|
||||
const struct mode* mode_list[16] = {
|
||||
NULL, // dummy 0 entry
|
||||
&m_01_default,
|
||||
&m_02_default2,
|
||||
//&m_02_default2,
|
||||
NULL, // terminating entry
|
||||
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -55,12 +54,12 @@ void modes_init(void) {
|
|||
#else
|
||||
tusb_got[tusbgot_cdc_line_coding ] = NULL;
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
tusb_got[tusbgot_vendor_control_xfer] =
|
||||
ORDEF(mode_default->tud_vendor_control_xfer_cb, mode_std_vendor_control_xfer_cb);
|
||||
#else
|
||||
tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
#endif
|
||||
//#else
|
||||
// tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
//#endif
|
||||
|
||||
tusb_got[tusbgot_hid_descriptor_report ] =
|
||||
ORDEF(mode_default->tud_hid_descriptor_report_cb, mode_std_hid_descriptor_report_cb);
|
||||
|
@ -107,12 +106,12 @@ void modes_switch(uint8_t newmode) {
|
|||
#else
|
||||
tusb_got[tusbgot_cdc_line_coding ] = NULL;
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
tusb_got[tusbgot_vendor_control_xfer] =
|
||||
ORDEF(mode_current->tud_vendor_control_xfer_cb, mode_std_vendor_control_xfer_cb);
|
||||
#else
|
||||
tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
#endif
|
||||
//#else
|
||||
// tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
//#endif
|
||||
|
||||
tusb_got[tusbgot_hid_descriptor_report ] =
|
||||
ORDEF(mode_current->tud_hid_descriptor_report_cb, mode_std_hid_descriptor_report_cb);
|
||||
|
@ -137,11 +136,11 @@ void modes_switch(uint8_t newmode) {
|
|||
#else
|
||||
tusb_got[tusbgot_cdc_line_coding ] = NULL;
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
tusb_got[tusbgot_vendor_control_xfer] = mode_std_vendor_control_xfer_cb;
|
||||
#else
|
||||
tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
#endif
|
||||
//#else
|
||||
// tusb_got[tusbgot_vendor_control_xfer] = NULL;
|
||||
//#endif
|
||||
|
||||
tusb_got[tusbgot_hid_descriptor_report ] = mode_std_hid_descriptor_report_cb;
|
||||
tusb_got[tusbgot_descriptor_device ] = mode_std_descriptor_device_cb;
|
||||
|
|
32
src/thread.c
32
src/thread.c
|
@ -1,6 +1,8 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
|
@ -11,6 +13,32 @@ cothread_t co_active_handle;
|
|||
|
||||
static cothread_t mainthread;
|
||||
|
||||
void thread_init (void) { mainthread = co_active(); }
|
||||
void thread_yield(void) { co_switch(mainthread); }
|
||||
static cothread_t threadarr[16]; /* 16 nested threads should be enough... */
|
||||
static size_t threadind;
|
||||
|
||||
void thread_init(void) {
|
||||
memset(threadarr, 0, sizeof threadarr);
|
||||
|
||||
mainthread = co_active();
|
||||
threadarr[0] = mainthread;
|
||||
threadind = 0;
|
||||
}
|
||||
|
||||
void thread_yield(void) {
|
||||
/*cothread_t newthrd = threadarr[threadind];
|
||||
if (threadind > 0) --threadind;*/
|
||||
|
||||
co_switch(mainthread/*newthrd*/);
|
||||
}
|
||||
|
||||
void thread_enter(cothread_t thrid) {
|
||||
/*if (threadind + 1 == sizeof(threadarr) / sizeof(threadarr[0])) {
|
||||
// TODO: PANIC!
|
||||
}
|
||||
|
||||
threadarr[threadind] = co_active();
|
||||
++threadind;*/
|
||||
|
||||
co_switch(thrid);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,10 @@
|
|||
void thread_init (void);
|
||||
void thread_yield(void);
|
||||
|
||||
/* thread_enter + thread_yield can be used to "call" threads in a stack-like
|
||||
* way, much like functions. this is needed because vnd_cfg might call mode
|
||||
* stuff which might do stuff in its own tasks and so on. */
|
||||
void thread_enter(cothread_t thrid);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
//#include "protocfg.h"
|
||||
#include "bsp-info.h"
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
|
@ -107,14 +107,7 @@ extern "C" {
|
|||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_NET 0
|
||||
// see also: bsp/<family>/protocfg.h
|
||||
#define CFG_TUD_HID 0
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define CFG_TUD_CDC 1
|
||||
#else
|
||||
#define CFG_TUD_CDC 0
|
||||
#endif
|
||||
#define CFG_TUD_VENDOR 1
|
||||
// see also: bsp/<family>/bsp-info.h
|
||||
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
#include "tusb_config.h"
|
||||
#include <tusb.h>
|
||||
|
||||
#include "info.h"
|
||||
#include "mode.h"
|
||||
|
||||
#include "protocfg.h"
|
||||
#include "util.h"
|
||||
|
||||
#define USB_BCD_BASE 0x8000
|
||||
|
@ -22,22 +21,41 @@ enum {
|
|||
|
||||
STRID_CONFIG,
|
||||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
STRID_IF_VND_CFG,
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
STRID_IF_CDC_STDIO,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
ITF_NUM_VND_CFG,
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
ITF_NUM_CDC_STDIO_COM,
|
||||
ITF_NUM_CDC_STDIO_DATA,
|
||||
#endif
|
||||
|
||||
ITF_NUM__TOTAL
|
||||
};
|
||||
enum {
|
||||
CONFIG_TOTAL_LEN
|
||||
= TUD_CONFIG_DESC_LEN
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
+ TUD_VENDOR_DESC_LEN
|
||||
#endif
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
+ TUD_CDC_DESC_LEN
|
||||
#endif
|
||||
};
|
||||
|
||||
#define EPNUM_VND_CFG_OUT 0x02
|
||||
#define EPNUM_VND_CFG_IN 0x82
|
||||
#define EPNUM_VND_CFG_OUT 0x01
|
||||
#define EPNUM_VND_CFG_IN 0x81
|
||||
#define EPNUM_CDC_STDIO_OUT 0x02
|
||||
#define EPNUM_CDC_STDIO_IN 0x82
|
||||
#define EPNUM_CDC_STDIO_NOTIF 0x83
|
||||
|
||||
// clang-format off
|
||||
static const tusb_desc_device_t desc_device = {
|
||||
|
@ -73,8 +91,15 @@ static const uint8_t desc_configuration[] = {
|
|||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
|
||||
EPNUM_VND_CFG_IN, 64),
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64,
|
||||
EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64),
|
||||
#endif
|
||||
};
|
||||
static const char* string_desc_arr[] = {
|
||||
[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409)
|
||||
|
@ -83,6 +108,7 @@ static const char* string_desc_arr[] = {
|
|||
|
||||
[STRID_CONFIG] = "Configuration descriptor",
|
||||
[STRID_IF_VND_CFG] = "Device cfg/ctl interface",
|
||||
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -106,6 +132,7 @@ void mode_std_hid_set_report_cb(uint8_t instance, uint8_t report_id,
|
|||
(void)instance;
|
||||
(void)report_id;
|
||||
(void)report_type;
|
||||
(void)rx_data_buffer;
|
||||
|
||||
tud_hid_report(0, tx_data_buffer, response_size);
|
||||
}
|
||||
|
@ -116,7 +143,7 @@ void mode_std_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_codi
|
|||
(void)line_coding;
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
//#if CFG_TUD_VENDOR > 0
|
||||
bool mode_std_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
||||
tusb_control_request_t const* req) {
|
||||
(void)rhport;
|
||||
|
@ -125,7 +152,7 @@ bool mode_std_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
const uint8_t* mode_std_hid_descriptor_report_cb(uint8_t instance) {
|
||||
(void)instance;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "thread.h"
|
||||
|
||||
#if CFG_TUD_VENDOR > 0
|
||||
static uint8_t rx_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
static uint8_t tx_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
|
||||
|
@ -144,4 +145,14 @@ void vnd_cfg_task(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else /* CFG_TUD_VENDOR == 0 */
|
||||
void vnd_cfg_init(void) { }
|
||||
uint8_t vnd_cfg_read_byte(void) { return 0xff; }
|
||||
void vnd_cfg_write_flush(void) { }
|
||||
void vnd_cfg_write_byte(uint8_t v) { (void)v; }
|
||||
void vnd_cfg_write_resp(enum cfg_resp stat, uint16_t len, const void* data) {
|
||||
(void)stat; (void)len; (void)data;
|
||||
}
|
||||
void vnd_cfg_task(void) { }
|
||||
#endif /* CFG_TUD_VENDOR */
|
||||
|
||||
|
|
Loading…
Reference in New Issue