Added RP2040 support

This commit is contained in:
Alex Taradov 2022-01-04 19:28:52 -08:00
parent a720420a78
commit 83f02325ed
30 changed files with 35393 additions and 0 deletions

View File

@ -0,0 +1,242 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _DAP_CONFIG_H_
#define _DAP_CONFIG_H_
/*- Includes ----------------------------------------------------------------*/
#include "rp2040.h"
#include "hal_config.h"
/*- Definitions -------------------------------------------------------------*/
#define DAP_CONFIG_ENABLE_JTAG
#define DAP_CONFIG_DEFAULT_PORT DAP_PORT_SWD
#define DAP_CONFIG_DEFAULT_CLOCK 1000000 // Hz
#define DAP_CONFIG_PACKET_SIZE 64
#define DAP_CONFIG_PACKET_COUNT 1
#define DAP_CONFIG_JTAG_DEV_COUNT 8
// Set the value to NULL if you want to disable a string
// DAP_CONFIG_PRODUCT_STR must contain "CMSIS-DAP" to be compatible with the standard
#define DAP_CONFIG_VENDOR_STR "Alex Taradov"
#define DAP_CONFIG_PRODUCT_STR "Generic CMSIS-DAP Adapter"
#define DAP_CONFIG_SER_NUM_STR usb_serial_number
#define DAP_CONFIG_FW_VER_STR "v1.0"
#define DAP_CONFIG_DEVICE_VENDOR_STR NULL
#define DAP_CONFIG_DEVICE_NAME_STR NULL
//#define DAP_CONFIG_RESET_TARGET_FN target_specific_reset_function
//#define DAP_CONFIG_VENDOR_FN vendor_command_handler_function
// Attribute to use for performance-critical functions
#define DAP_CONFIG_PERFORMANCE_ATTR
// A value at which dap_clock_test() produces 1 kHz output on the SWCLK pin
#define DAP_CONFIG_DELAY_CONSTANT 20000
// A threshold for switching to fast clock (no added delays)
// This is the frequency produced by dap_clock_test(1) on the SWCLK pin
#define DAP_CONFIG_FAST_CLOCK 8550000 // Hz
/*- Prototypes --------------------------------------------------------------*/
extern char usb_serial_number[16];
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_write(int value)
{
HAL_GPIO_SWCLK_TCK_write(value);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_write(int value)
{
HAL_GPIO_SWDIO_TMS_write(value);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_TDI_write(int value)
{
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDI_write(value);
#else
(void)value;
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_TDO_write(int value)
{
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDO_write(value);
#else
(void)value;
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_nTRST_write(int value)
{
(void)value;
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_nRESET_write(int value)
{
HAL_GPIO_nRESET_write(value);
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_SWCLK_TCK_read(void)
{
return HAL_GPIO_SWCLK_TCK_read();
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_SWDIO_TMS_read(void)
{
return HAL_GPIO_SWDIO_TMS_read();
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_TDO_read(void)
{
#ifdef DAP_CONFIG_ENABLE_JTAG
return HAL_GPIO_TDO_read();
#else
return 0;
#endif
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_TDI_read(void)
{
#ifdef DAP_CONFIG_ENABLE_JTAG
return HAL_GPIO_TDI_read();
#else
return 0;
#endif
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_nTRST_read(void)
{
return 0;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_nRESET_read(void)
{
return HAL_GPIO_nRESET_read();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_set(void)
{
HAL_GPIO_SWCLK_TCK_set();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_clr(void)
{
HAL_GPIO_SWCLK_TCK_clr();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_in(void)
{
HAL_GPIO_SWDIO_TMS_in();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_out(void)
{
HAL_GPIO_SWDIO_TMS_out();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SETUP(void)
{
HAL_GPIO_SWCLK_TCK_in();
HAL_GPIO_SWDIO_TMS_in();
HAL_GPIO_nRESET_in();
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDO_in();
HAL_GPIO_TDI_in();
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_DISCONNECT(void)
{
HAL_GPIO_SWCLK_TCK_in();
HAL_GPIO_SWDIO_TMS_in();
HAL_GPIO_nRESET_in();
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDO_in();
HAL_GPIO_TDI_in();
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_CONNECT_SWD(void)
{
HAL_GPIO_SWDIO_TMS_out();
HAL_GPIO_SWDIO_TMS_set();
HAL_GPIO_SWCLK_TCK_out();
HAL_GPIO_SWCLK_TCK_set();
HAL_GPIO_nRESET_out();
HAL_GPIO_nRESET_set();
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDO_in();
HAL_GPIO_TDI_in();
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_CONNECT_JTAG(void)
{
HAL_GPIO_SWDIO_TMS_out();
HAL_GPIO_SWDIO_TMS_set();
HAL_GPIO_SWCLK_TCK_out();
HAL_GPIO_SWCLK_TCK_set();
HAL_GPIO_nRESET_out();
HAL_GPIO_nRESET_set();
#ifdef DAP_CONFIG_ENABLE_JTAG
HAL_GPIO_TDO_in();
HAL_GPIO_TDI_out();
HAL_GPIO_TDI_set();
#endif
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_LED(int index, int state)
{
(void)index;
(void)state;
}
//-----------------------------------------------------------------------------
__attribute__((always_inline))
static inline void DAP_CONFIG_DELAY(uint32_t cycles)
{
asm volatile (
"1: sub %[cycles], %[cycles], #1 \n"
" bne 1b \n"
: [cycles] "+l"(cycles)
);
}
#endif // _DAP_CONFIG_H_

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _HAL_CONFIG_H_
#define _HAL_CONFIG_H_
/*- Includes ----------------------------------------------------------------*/
#include "hal_gpio.h"
/*- Definitions -------------------------------------------------------------*/
HAL_GPIO_PIN(SWCLK_TCK, 0, 11, sio_11)
HAL_GPIO_PIN(SWDIO_TMS, 0, 12, sio_12)
HAL_GPIO_PIN(TDI, 0, 13, sio_13)
HAL_GPIO_PIN(TDO, 0, 14, sio_14)
HAL_GPIO_PIN(nRESET, 0, 15, sio_15)
HAL_GPIO_PIN(VCP_STATUS, 0, 6, sio_6);
HAL_GPIO_PIN(DAP_STATUS, 0, 7, sio_7);
HAL_GPIO_PIN(UART_TX, 0, 0, uart0_tx)
HAL_GPIO_PIN(UART_RX, 0, 1, uart0_rx)
#define UART_PER UART0
#define UART_RESET_MASK RESETS_RESET_uart0_Msk
#define UART_IRQ_INDEX UART0_IRQ_IRQn
#define UART_IRQ_HANDLER irq_handler_uart0
#define UART_CLOCK 120000000
#endif // _HAL_CONFIG_H_

View File

@ -0,0 +1,85 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _HAL_GPIO_H_
#define _HAL_GPIO_H_
/*- Definitions -------------------------------------------------------------*/
#define HAL_GPIO_PIN(name, port, pin, func) \
static inline void HAL_GPIO_##name##_set(void) \
{ \
SIO->GPIO_OUT_SET = (1 << pin); \
(void)HAL_GPIO_##name##_set; \
} \
\
static inline void HAL_GPIO_##name##_clr(void) \
{ \
SIO->GPIO_OUT_CLR = (1 << pin); \
(void)HAL_GPIO_##name##_clr; \
} \
\
static inline void HAL_GPIO_##name##_toggle(void) \
{ \
SIO->GPIO_OUT_XOR = (1 << pin); \
(void)HAL_GPIO_##name##_toggle; \
} \
\
static inline void HAL_GPIO_##name##_write(int value) \
{ \
if (value) \
SIO->GPIO_OUT_SET = (1 << pin); \
else \
SIO->GPIO_OUT_CLR = (1 << pin); \
(void)HAL_GPIO_##name##_write; \
} \
\
static inline void HAL_GPIO_##name##_in(void) \
{ \
SIO->GPIO_OE_CLR = (1 << pin); \
IO_BANK##port->GPIO##pin##_CTRL = IO_BANK##port##_GPIO##pin##_CTRL_FUNCSEL_sio_##pin; \
PADS_BANK##port##_CLR->GPIO##pin = PADS_BANK##port##_GPIO##pin##_PDE_Msk | PADS_BANK##port##_GPIO##pin##_PUE_Msk; \
PADS_BANK##port##_SET->GPIO##pin = PADS_BANK##port##_GPIO##pin##_IE_Msk; \
(void)HAL_GPIO_##name##_in; \
} \
\
static inline void HAL_GPIO_##name##_out(void) \
{ \
SIO->GPIO_OE_SET = (1 << pin); \
IO_BANK##port->GPIO##pin##_CTRL = IO_BANK##port##_GPIO##pin##_CTRL_FUNCSEL_sio_##pin; \
(void)HAL_GPIO_##name##_out; \
} \
\
static inline void HAL_GPIO_##name##_init(void) \
{ \
IO_BANK##port->GPIO##pin##_CTRL = IO_BANK##port##_GPIO##pin##_CTRL_FUNCSEL_##func; \
(void)HAL_GPIO_##name##_init; \
} \
\
static inline void HAL_GPIO_##name##_pullup(void) \
{ \
PADS_BANK##port##_SET->GPIO##pin = PADS_BANK##port##_GPIO##pin##_PUE_Msk; \
PADS_BANK##port##_CLR->GPIO##pin = PADS_BANK##port##_GPIO##pin##_PDE_Msk; \
(void)HAL_GPIO_##name##_pullup; \
} \
\
static inline void HAL_GPIO_##name##_pulldown(void) \
{ \
PADS_BANK##port##_SET->GPIO##pin = PADS_BANK##port##_GPIO##pin##_PDE_Msk; \
PADS_BANK##port##_CLR->GPIO##pin = PADS_BANK##port##_GPIO##pin##_PUE_Msk; \
(void)HAL_GPIO_##name##_pulldown; \
} \
\
static inline int HAL_GPIO_##name##_read(void) \
{ \
return (SIO->GPIO_IN & (1 << pin)) != 0; \
(void)HAL_GPIO_##name##_read; \
} \
\
static inline void HAL_GPIO_##name##_funcsel(int fn) \
{ \
IO_BANK##port->GPIO##pin##_CTRL_b.FUNCSEL = fn; \
(void)HAL_GPIO_##name##_funcsel; \
} \
#endif // _HAL_GPIO_H_

View File

@ -0,0 +1,283 @@
/**************************************************************************//**
* @file cmsis_compiler.h
* @brief CMSIS compiler generic header file
* @version V5.1.0
* @date 09. October 2018
******************************************************************************/
/*
* Copyright (c) 2009-2018 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CMSIS_COMPILER_H
#define __CMSIS_COMPILER_H
#include <stdint.h>
/*
* Arm Compiler 4/5
*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*
* Arm Compiler 6.6 LTM (armclang)
*/
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100)
#include "cmsis_armclang_ltm.h"
/*
* Arm Compiler above 6.10.1 (armclang)
*/
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
#include "cmsis_armclang.h"
/*
* GNU Compiler
*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*
* IAR Compiler
*/
#elif defined ( __ICCARM__ )
#include <cmsis_iccarm.h>
/*
* TI Arm Compiler
*/
#elif defined ( __TI_ARM__ )
#include <cmsis_ccs.h>
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
#define __NO_RETURN __attribute__((noreturn))
#endif
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __attribute__((packed))
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __attribute__((packed))
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __attribute__((packed))
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
struct __attribute__((packed)) T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#ifndef __RESTRICT
#define __RESTRICT __restrict
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
/*
* TASKING Compiler
*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
#define __NO_RETURN __attribute__((noreturn))
#endif
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __packed__
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __packed__
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __packed__
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
struct __packed__ T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __align(x)
#endif
#ifndef __RESTRICT
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
#define __RESTRICT
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
/*
* COSMIC Compiler
*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#ifndef __ASM
#define __ASM _asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
// NO RETURN is automatically detected hence no warning here
#define __NO_RETURN
#endif
#ifndef __USED
#warning No compiler specific solution for __USED. __USED is ignored.
#define __USED
#endif
#ifndef __WEAK
#define __WEAK __weak
#endif
#ifndef __PACKED
#define __PACKED @packed
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT @packed struct
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION @packed union
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
@packed struct T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.
#define __ALIGNED(x)
#endif
#ifndef __RESTRICT
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
#define __RESTRICT
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
#else
#error Unknown compiler.
#endif
#endif /* __CMSIS_COMPILER_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/**************************************************************************//**
* @file cmsis_version.h
* @brief CMSIS Core(M) Version definitions
* @version V5.0.4
* @date 23. July 2019
******************************************************************************/
/*
* Copyright (c) 2009-2019 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CMSIS_VERSION_H
#define __CMSIS_VERSION_H
/* CMSIS Version definitions */
#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */
#define __CM_CMSIS_VERSION_SUB ( 4U) /*!< [15:0] CMSIS Core(M) sub version */
#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \
__CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,275 @@
/******************************************************************************
* @file mpu_armv7.h
* @brief CMSIS MPU API for Armv7-M MPU
* @version V5.1.2
* @date 25. May 2020
******************************************************************************/
/*
* Copyright (c) 2017-2020 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef ARM_MPU_ARMV7_H
#define ARM_MPU_ARMV7_H
#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes
#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access
#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only
#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only
#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access
#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only
#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access
/** MPU Region Base Address Register Value
*
* \param Region The region to be configured, number 0 to 15.
* \param BaseAddress The base address for the region.
*/
#define ARM_MPU_RBAR(Region, BaseAddress) \
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
((Region) & MPU_RBAR_REGION_Msk) | \
(MPU_RBAR_VALID_Msk))
/**
* MPU Memory Access Attributes
*
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
*/
#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \
((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
(((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
(((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
(((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \
((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
(((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \
(((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \
(((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \
(((MPU_RASR_ENABLE_Msk))))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)
/**
* MPU Memory Access Attribute for strongly ordered memory.
* - TEX: 000b
* - Shareable
* - Non-cacheable
* - Non-bufferable
*/
#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)
/**
* MPU Memory Access Attribute for device memory.
* - TEX: 000b (if shareable) or 010b (if non-shareable)
* - Shareable or non-shareable
* - Non-cacheable
* - Bufferable (if shareable) or non-bufferable (if non-shareable)
*
* \param IsShareable Configures the device memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))
/**
* MPU Memory Access Attribute for normal memory.
* - TEX: 1BBb (reflecting outer cacheability rules)
* - Shareable or non-shareable
* - Cacheable or non-cacheable (reflecting inner cacheability rules)
* - Bufferable or non-bufferable (reflecting inner cacheability rules)
*
* \param OuterCp Configures the outer cache policy.
* \param InnerCp Configures the inner cache policy.
* \param IsShareable Configures the memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) >> 1U), ((InnerCp) & 1U))
/**
* MPU Memory Access Attribute non-cacheable policy.
*/
#define ARM_MPU_CACHEP_NOCACHE 0U
/**
* MPU Memory Access Attribute write-back, write and read allocate policy.
*/
#define ARM_MPU_CACHEP_WB_WRA 1U
/**
* MPU Memory Access Attribute write-through, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WT_NWA 2U
/**
* MPU Memory Access Attribute write-back, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WB_NWA 3U
/**
* Struct for a single MPU Region
*/
typedef struct {
uint32_t RBAR; //!< The region base address register value (RBAR)
uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR
} ARM_MPU_Region_t;
/** Enable the MPU.
* \param MPU_Control Default access permissions for unconfigured regions.
*/
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
{
__DMB();
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
#endif
__DSB();
__ISB();
}
/** Disable the MPU.
*/
__STATIC_INLINE void ARM_MPU_Disable(void)
{
__DMB();
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
#endif
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
__DSB();
__ISB();
}
/** Clear and disable the given MPU region.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
{
MPU->RNR = rnr;
MPU->RASR = 0U;
}
/** Configure an MPU region.
* \param rbar Value for RBAR register.
* \param rasr Value for RASR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)
{
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Configure the given MPU region.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rasr Value for RASR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)
{
MPU->RNR = rnr;
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_Load().
* \param dst Destination data is copied to.
* \param src Source data is copied from.
* \param len Amount of data words to be copied.
*/
__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
{
uint32_t i;
for (i = 0U; i < len; ++i)
{
dst[i] = src[i];
}
}
/** Load the given number of MPU regions from a table.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt)
{
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
while (cnt > MPU_TYPE_RALIASES) {
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);
table += MPU_TYPE_RALIASES;
cnt -= MPU_TYPE_RALIASES;
}
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
/*
SPDX-License-Identifier: BSD-3-Clause
Copyright (c) 2021, Alex Taradov <alex@taradov.com>. All rights reserved.
*/
MEMORY
{
boot (rx) : ORIGIN = 0x10000000, LENGTH = 256
flash (rx) : ORIGIN = 0x10000100, LENGTH = 2048K - 256
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
ENTRY(boot_entry)
SECTIONS
{
.boot : ALIGN(4)
{
KEEP(*(.boot.entry))
*(.boot*)
. = 256-4;
LONG(0xcccccccc) /* CRC */
} > boot
.text : ALIGN(4)
{
_text = .;
KEEP(*(.vectors))
*(.text*)
*(.rodata)
*(.rodata.*)
. = ALIGN(4);
_etext = .;
} > ram AT > flash
.data : ALIGN(4)
{
_data = .;
*(.ramfunc .ramfunc.*);
*(vtable)
*(.data*)
. = ALIGN(4);
_edata = .;
} > ram AT > flash
.bss : ALIGN(4)
{
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} > ram
PROVIDE(_end = .);
PROVIDE(_text_start = ORIGIN(flash));
PROVIDE(_stack_top = ORIGIN(ram) + LENGTH(ram));
}

371
platform/rp2040/main.c Normal file
View File

@ -0,0 +1,371 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rp2040.h"
#include "hal_gpio.h"
#include "usb.h"
#include "uart.h"
#include "dap.h"
#include "dap_config.h"
/*- Definitions -------------------------------------------------------------*/
#define USB_BUFFER_SIZE 64
#define UART_WAIT_TIMEOUT 10 // ms
#define STATUS_TIMEOUT 250 // ms
#define F_REF 12000000
#define F_CPU 120000000
#define F_PER 120000000
#define F_RTC (F_REF / 256)
#define F_TICK 1000000
/*- Variables ---------------------------------------------------------------*/
static uint8_t app_request_buffer[DAP_CONFIG_PACKET_SIZE];
static uint8_t app_response_buffer[DAP_CONFIG_PACKET_SIZE];
static uint8_t app_recv_buffer[USB_BUFFER_SIZE];
static uint8_t app_send_buffer[USB_BUFFER_SIZE];
static int app_recv_buffer_size = 0;
static int app_recv_buffer_ptr = 0;
static int app_send_buffer_ptr = 0;
static bool app_send_buffer_free = true;
static bool app_send_zlp = false;
static uint64_t app_system_time = 0;
static uint64_t app_uart_timeout = 0;
static uint64_t app_status_timeout = 0;
static uint64_t app_break_timeout = 0;
static bool app_dap_event = false;
static bool app_vcp_event = false;
static bool app_vcp_open = false;
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
static void sys_init(void)
{
// Enable XOSC
XOSC->CTRL = (XOSC_CTRL_FREQ_RANGE_1_15MHZ << XOSC_CTRL_FREQ_RANGE_Pos);
XOSC->STARTUP = 47; // ~1 ms @ 12 MHz
XOSC_SET->CTRL = (XOSC_CTRL_ENABLE_ENABLE << XOSC_CTRL_ENABLE_Pos);
while (0 == (XOSC->STATUS & XOSC_STATUS_STABLE_Msk));
// Setup SYS PLL for 12 MHz * 40 / 4 / 1 = 120 MHz
RESETS_CLR->RESET = RESETS_RESET_pll_sys_Msk;
while (0 == RESETS->RESET_DONE_b.pll_sys);
PLL_SYS->CS = (1 << PLL_SYS_CS_REFDIV_Pos);
PLL_SYS->FBDIV_INT = 40;
PLL_SYS->PRIM = (4 << PLL_SYS_PRIM_POSTDIV1_Pos) | (1 << PLL_SYS_PRIM_POSTDIV2_Pos);
PLL_SYS_CLR->PWR = PLL_SYS_PWR_VCOPD_Msk | PLL_SYS_PWR_PD_Msk;
while (0 == PLL_SYS->CS_b.LOCK);
PLL_SYS_CLR->PWR = PLL_SYS_PWR_POSTDIVPD_Msk;
// Setup USB PLL for 12 MHz * 36 / 3 / 3 = 48 MHz
RESETS_CLR->RESET = RESETS_RESET_pll_usb_Msk;
while (0 == RESETS->RESET_DONE_b.pll_usb);
PLL_USB->CS = (1 << PLL_SYS_CS_REFDIV_Pos);
PLL_USB->FBDIV_INT = 36;
PLL_USB->PRIM = (3 << PLL_SYS_PRIM_POSTDIV1_Pos) | (3 << PLL_SYS_PRIM_POSTDIV2_Pos);
PLL_USB_CLR->PWR = PLL_SYS_PWR_VCOPD_Msk | PLL_SYS_PWR_PD_Msk;
while (0 == PLL_USB->CS_b.LOCK);
PLL_USB_CLR->PWR = PLL_SYS_PWR_POSTDIVPD_Msk;
// Switch clocks to their final socurces
CLOCKS->CLK_REF_CTRL = (CLOCKS_CLK_REF_CTRL_SRC_xosc_clksrc << CLOCKS_CLK_REF_CTRL_SRC_Pos);
CLOCKS->CLK_SYS_CTRL = (CLOCKS_CLK_SYS_CTRL_AUXSRC_clksrc_pll_sys << CLOCKS_CLK_SYS_CTRL_AUXSRC_Pos);
CLOCKS_SET->CLK_SYS_CTRL = (CLOCKS_CLK_SYS_CTRL_SRC_clksrc_clk_sys_aux << CLOCKS_CLK_SYS_CTRL_SRC_Pos);
CLOCKS->CLK_PERI_CTRL = CLOCKS_CLK_PERI_CTRL_ENABLE_Msk |
(CLOCKS_CLK_PERI_CTRL_AUXSRC_clk_sys << CLOCKS_CLK_PERI_CTRL_AUXSRC_Pos);
CLOCKS->CLK_USB_CTRL = CLOCKS_CLK_USB_CTRL_ENABLE_Msk |
(CLOCKS_CLK_USB_CTRL_AUXSRC_clksrc_pll_usb << CLOCKS_CLK_USB_CTRL_AUXSRC_Pos);
CLOCKS->CLK_ADC_CTRL = CLOCKS_CLK_ADC_CTRL_ENABLE_Msk |
(CLOCKS_CLK_ADC_CTRL_AUXSRC_clksrc_pll_usb << CLOCKS_CLK_ADC_CTRL_AUXSRC_Pos);
CLOCKS->CLK_RTC_DIV = (256 << CLOCKS_CLK_RTC_DIV_INT_Pos); // 12MHz / 256 = 46875 Hz
CLOCKS->CLK_RTC_CTRL = CLOCKS_CLK_RTC_CTRL_ENABLE_Msk |
(CLOCKS_CLK_RTC_CTRL_AUXSRC_xosc_clksrc << CLOCKS_CLK_ADC_CTRL_AUXSRC_Pos);
// Configure 1 us tick for watchdog and timer
WATCHDOG->TICK = ((F_REF/F_TICK) << WATCHDOG_TICK_CYCLES_Pos) | WATCHDOG_TICK_ENABLE_Msk;
// Enable GPIOs
RESETS_CLR->RESET = RESETS_RESET_io_bank0_Msk | RESETS_RESET_pads_bank0_Msk;
while (0 == RESETS->RESET_DONE_b.io_bank0 || 0 == RESETS->RESET_DONE_b.pads_bank0);
}
//-----------------------------------------------------------------------------
static void serial_number_init(void)
{
volatile uint8_t *uid = (volatile uint8_t *)0x20041f01;
uint32_t sn = 5381;
for (int i = 0; i < 16; i++)
sn = ((sn << 5) + sn) ^ uid[i];
for (int i = 0; i < 8; i++)
usb_serial_number[i] = "0123456789ABCDEF"[(sn >> (i * 4)) & 0xf];
usb_serial_number[8] = 0;
}
//-----------------------------------------------------------------------------
static void sys_time_init(void)
{
SysTick->VAL = 0;
SysTick->LOAD = 1000; // 1 ms
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
app_system_time = 0;
}
//-----------------------------------------------------------------------------
static void sys_time_task(void)
{
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)
app_system_time++;
}
//-----------------------------------------------------------------------------
static void tx_task(void)
{
while (app_recv_buffer_size)
{
if (!uart_write_byte(app_recv_buffer[app_recv_buffer_ptr]))
break;
app_recv_buffer_ptr++;
app_recv_buffer_size--;
app_vcp_event = true;
if (0 == app_recv_buffer_size)
usb_cdc_recv(app_recv_buffer, sizeof(app_recv_buffer));
}
}
//-----------------------------------------------------------------------------
static void send_buffer(void)
{
app_send_buffer_free = false;
app_send_zlp = (USB_BUFFER_SIZE == app_send_buffer_ptr);
usb_cdc_send(app_send_buffer, app_send_buffer_ptr);
app_send_buffer_ptr = 0;
}
//-----------------------------------------------------------------------------
static void rx_task(void)
{
int byte;
if (!app_send_buffer_free)
return;
while (uart_read_byte(&byte))
{
int state = (byte >> 8) & 0xff;
app_uart_timeout = app_system_time + UART_WAIT_TIMEOUT;
app_vcp_event = true;
if (state)
{
usb_cdc_set_state(state);
}
else
{
app_send_buffer[app_send_buffer_ptr++] = byte;
if (USB_BUFFER_SIZE == app_send_buffer_ptr)
{
send_buffer();
break;
}
}
}
}
//-----------------------------------------------------------------------------
static void break_task(void)
{
if (app_break_timeout && app_system_time > app_break_timeout)
{
uart_set_break(false);
app_break_timeout = 0;
}
}
//-----------------------------------------------------------------------------
static void uart_timer_task(void)
{
if (app_uart_timeout && app_system_time > app_uart_timeout)
{
if (app_send_zlp || app_send_buffer_ptr)
send_buffer();
app_uart_timeout = 0;
}
}
//-----------------------------------------------------------------------------
void usb_cdc_line_coding_updated(usb_cdc_line_coding_t *line_coding)
{
uart_init(line_coding);
}
//-----------------------------------------------------------------------------
void usb_cdc_control_line_state_update(int line_state)
{
bool status = line_state & USB_CDC_CTRL_SIGNAL_DTE_PRESENT;
app_vcp_open = status;
app_send_buffer_ptr = 0;
app_uart_timeout = 0;
app_break_timeout = 0;
if (app_vcp_open)
uart_init(usb_cdc_get_line_coding());
else
uart_close();
}
//-----------------------------------------------------------------------------
void usb_cdc_send_break(int duration)
{
if (USB_CDC_BREAK_DURATION_DISABLE == duration)
{
app_break_timeout = 0;
uart_set_break(false);
}
else if (USB_CDC_BREAK_DURATION_INFINITE == duration)
{
app_break_timeout = 0;
uart_set_break(true);
}
else
{
app_break_timeout = app_system_time + duration;
uart_set_break(true);
}
}
//-----------------------------------------------------------------------------
void usb_cdc_send_callback(void)
{
app_send_buffer_free = true;
}
//-----------------------------------------------------------------------------
void usb_cdc_recv_callback(int size)
{
app_recv_buffer_ptr = 0;
app_recv_buffer_size = size;
}
//-----------------------------------------------------------------------------
void usb_hid_send_callback(void)
{
usb_hid_recv(app_request_buffer, DAP_CONFIG_PACKET_SIZE);
}
//-----------------------------------------------------------------------------
void usb_hid_recv_callback(int size)
{
app_dap_event = true;
dap_process_request(app_request_buffer, sizeof(app_request_buffer),
app_response_buffer, sizeof(app_response_buffer));
usb_hid_send(app_response_buffer, sizeof(app_response_buffer));
(void)size;
}
//-----------------------------------------------------------------------------
bool usb_class_handle_request(usb_request_t *request)
{
if (usb_cdc_handle_request(request))
return true;
else if (usb_hid_handle_request(request))
return true;
else
return false;
}
//-----------------------------------------------------------------------------
void usb_configuration_callback(int config)
{
usb_cdc_recv(app_recv_buffer, sizeof(app_recv_buffer));
usb_hid_recv(app_request_buffer, sizeof(app_request_buffer));
app_send_buffer_free = true;
app_send_buffer_ptr = 0;
(void)config;
}
//-----------------------------------------------------------------------------
static void status_timer_task(void)
{
if (app_system_time < app_status_timeout)
return;
app_status_timeout = app_system_time + STATUS_TIMEOUT;
if (app_dap_event)
HAL_GPIO_DAP_STATUS_toggle();
else
HAL_GPIO_DAP_STATUS_set();
if (app_vcp_event)
HAL_GPIO_VCP_STATUS_toggle();
else
HAL_GPIO_VCP_STATUS_write(app_vcp_open);
app_dap_event = false;
app_vcp_event = false;
}
//-----------------------------------------------------------------------------
int main(void)
{
sys_init();
sys_time_init();
dap_init();
usb_init();
usb_cdc_init();
usb_hid_init();
serial_number_init();
app_status_timeout = STATUS_TIMEOUT;
HAL_GPIO_VCP_STATUS_out();
HAL_GPIO_VCP_STATUS_clr();
HAL_GPIO_DAP_STATUS_out();
HAL_GPIO_DAP_STATUS_set();
while (1)
{
sys_time_task();
usb_task();
tx_task();
rx_task();
break_task();
uart_timer_task();
status_timer_task();
}
return 0;
}

1
platform/rp2040/make/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,87 @@
##############################################################################
BUILD = build
BIN = free_dap_rp2040
##############################################################################
.PHONY: all directory clean size
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
ifeq ($(OS), Windows_NT)
MKDIR = gmkdir
else
MKDIR = mkdir
endif
CFLAGS += -W -Wall --std=gnu11 -Os
CFLAGS += -ffreestanding
CFLAGS += -fno-diagnostics-show-caret
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -funsigned-char -funsigned-bitfields
CFLAGS += -mcpu=cortex-m0plus -mthumb
CFLAGS += -MD -MP -MT $(BUILD)/$(*F).o -MF $(BUILD)/$(@F).d
LDFLAGS += -mcpu=cortex-m0plus -mthumb
LDFLAGS += -nostartfiles
LDFLAGS += -Wl,--gc-sections
LDFLAGS += -Wl,--script=../linker/rp2040.ld
INCLUDES += \
-I../include \
-I../../.. \
-I..
SRCS += \
../main.c \
../uart.c \
../usb.c \
../usb_std.c \
../usb_cdc.c \
../usb_hid.c \
../usb_descriptors.c \
../startup_rp2040.c \
../../../dap.c \
DEFINES += \
CFLAGS += $(INCLUDES) $(DEFINES)
OBJS = $(addprefix $(BUILD)/, $(notdir %/$(subst .c,.o, $(SRCS))))
all: directory $(BUILD)/$(BIN).elf $(BUILD)/$(BIN).hex $(BUILD)/$(BIN).bin $(BUILD)/$(BIN).uf2 size
$(BUILD)/$(BIN).elf: $(OBJS)
@echo LD $@
@$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(BUILD)/$(BIN).hex: $(BUILD)/$(BIN).elf
@echo OBJCOPY $@
@$(OBJCOPY) -O ihex $^ $@
$(BUILD)/$(BIN).bin: $(BUILD)/$(BIN).elf
@echo OBJCOPY $@
@$(OBJCOPY) -O binary $^ $@
$(BUILD)/$(BIN).uf2: $(BUILD)/$(BIN).bin
@echo BIN2UF2 $@
@bin2uf2 -i $^ -o $@
%.o:
@echo CC $@
@$(CC) $(CFLAGS) $(filter %/$(subst .o,.c,$(notdir $@)), $(SRCS)) -c -o $@
directory:
@$(MKDIR) -p $(BUILD)
size: $(BUILD)/$(BIN).elf
@echo size:
@$(SIZE) -t $^
clean:
@echo clean
@-rm -rf $(BUILD)
-include $(wildcard $(BUILD)/*.d)

View File

@ -0,0 +1,197 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, Alex Taradov <alex@taradov.com>. All rights reserved.
//-----------------------------------------------------------------------------
#include <stdint.h>
#include "rp2040.h"
//-----------------------------------------------------------------------------
#define DUMMY __attribute__ ((weak, alias ("irq_handler_dummy")))
//-----------------------------------------------------------------------------
DUMMY void irq_handler_nmi(void);
DUMMY void irq_handler_hard_fault(void);
DUMMY void irq_handler_sv_call(void);
DUMMY void irq_handler_pend_sv(void);
DUMMY void irq_handler_sys_tick(void);
DUMMY void irq_handler_timer_0(void);
DUMMY void irq_handler_timer_1(void);
DUMMY void irq_handler_timer_2(void);
DUMMY void irq_handler_timer_3(void);
DUMMY void irq_handler_pwm(void);
DUMMY void irq_handler_usbctrl(void);
DUMMY void irq_handler_xip(void);
DUMMY void irq_handler_pio0_0(void);
DUMMY void irq_handler_pio0_1(void);
DUMMY void irq_handler_pio1_0(void);
DUMMY void irq_handler_pio1_1(void);
DUMMY void irq_handler_dma_0(void);
DUMMY void irq_handler_dma_1(void);
DUMMY void irq_handler_io_bank0(void);
DUMMY void irq_handler_io_qspi(void);
DUMMY void irq_handler_sio_proc0(void);
DUMMY void irq_handler_sio_proc1(void);
DUMMY void irq_handler_clocks(void);
DUMMY void irq_handler_spi0(void);
DUMMY void irq_handler_spi1(void);
DUMMY void irq_handler_uart0(void);
DUMMY void irq_handler_uart1(void);
DUMMY void irq_handler_adc_fifo(void);
DUMMY void irq_handler_i2c0(void);
DUMMY void irq_handler_i2c1(void);
DUMMY void irq_handler_rtc(void);
extern int main(void);
extern uint32_t _text_start;
extern uint32_t _stack_top;
extern uint32_t _text;
extern uint32_t _etext;
extern uint32_t _data;
extern uint32_t _edata;
extern uint32_t _bss;
extern uint32_t _ebss;
//-----------------------------------------------------------------------------
// Note: Vector table does not need to be placed in a separate section on this MCU,
// but we do so anyway to ensure alignment at 128 byte boundary without
// potentially wasting space with automatic alignment.
__attribute__ ((used, section(".vectors")))
void (* const vectors[])(void) =
{
0, // 0 - Initial Stack Pointer Value (unused)
// Cortex-M0+ handlers
0, // 1 - Reset (unused)
irq_handler_nmi, // 2 - NMI
irq_handler_hard_fault, // 3 - Hard Fault
0, // 4 - Reserved
0, // 5 - Reserved
0, // 6 - Reserved
0, // 7 - Reserved
0, // 8 - Reserved
0, // 9 - Reserved
0, // 10 - Reserved
irq_handler_sv_call, // 11 - SVCall
0, // 12 - Reserved
0, // 13 - Reserved
irq_handler_pend_sv, // 14 - PendSV
irq_handler_sys_tick, // 15 - SysTick
// Peripheral handlers
irq_handler_timer_0, // 0 - timer_irq_0
irq_handler_timer_1, // 1 - timer_irq_1
irq_handler_timer_2, // 2 - timer_irq_2
irq_handler_timer_3, // 3 - timer_irq_3
irq_handler_pwm, // 4 - pwm_irq_wrap
irq_handler_usbctrl, // 5 - usbctrl_irq
irq_handler_xip, // 6 - xip_irq
irq_handler_pio0_0, // 7 - pio0_irq_0
irq_handler_pio0_1, // 8 - pio0_irq_1
irq_handler_pio1_0, // 9 - pio1_irq_0
irq_handler_pio1_1, // 10 - pio1_irq_1
irq_handler_dma_0, // 11 - dma_irq_0
irq_handler_dma_1, // 12 - dma_irq_1
irq_handler_io_bank0, // 13 - io_irq_bank0
irq_handler_io_qspi, // 14 - io_irq_qspi
irq_handler_sio_proc0, // 15 - sio_irq_proc0
irq_handler_sio_proc1, // 16 - sio_irq_proc1
irq_handler_clocks, // 17 - clocks_irq
irq_handler_spi0, // 18 - spi0_irq
irq_handler_spi1, // 19 - spi1_irq
irq_handler_uart0, // 20 - uart0_irq
irq_handler_uart1, // 21 - uart1_irq
irq_handler_adc_fifo, // 22 - adc_irq_fifo
irq_handler_i2c0, // 23 - i2c0_irq
irq_handler_i2c1, // 24 - i2c1_irq
irq_handler_rtc, // 25 - rtc_irq
};
//-----------------------------------------------------------------------------
void irq_handler_dummy(void)
{
while (1);
}
//-----------------------------------------------------------------------------
__attribute__((naked, used, noreturn, section(".boot.entry"))) void boot_entry(void)
{
// Note: This code must be position independent, it is linked at 0x10000000, but
// loaded at 0x20041f00.
XIP_SSI->SSIENR = 0;
XIP_SSI->BAUDR = 2; // Must be even
// Read unique ID
XIP_SSI->RX_SAMPLE_DLY = (1 << XIP_SSI_RX_SAMPLE_DLY_RSD_Pos);
XIP_SSI->CTRLR0 = (XIP_SSI_CTRLR0_SPI_FRF_STD << XIP_SSI_CTRLR0_SPI_FRF_Pos) |
(XIP_SSI_CTRLR0_TMOD_TX_AND_RX << XIP_SSI_CTRLR0_TMOD_Pos) |
((32-1) << XIP_SSI_CTRLR0_DFS_32_Pos);
XIP_SSI->SSIENR = XIP_SSI_SSIENR_SSI_EN_Msk;
XIP_SSI->DR0 = 0x4b000000/*RUID*/;
XIP_SSI->DR0 = 0;
XIP_SSI->DR0 = 0;
XIP_SSI->DR0 = 0;
XIP_SSI->DR0 = 0;
XIP_SSI->DR0 = 0;
while (1)
{
int sr = XIP_SSI->SR;
if ((sr & XIP_SSI_SR_TFE_Msk) && (0 == (sr & XIP_SSI_SR_BUSY_Msk)))
break;
}
(void)XIP_SSI->DR0;
// UID is placed at the same address as this boot sector
volatile uint32_t *uid = (volatile uint32_t *)0x20041f00;
uid[0] = XIP_SSI->DR0;
uid[1] = XIP_SSI->DR0;
uid[2] = XIP_SSI->DR0;
uid[3] = XIP_SSI->DR0;
uid[4] = XIP_SSI->DR0;
XIP_SSI->SSIENR = 0;
// Setup for XIP
XIP_SSI->CTRLR0 = (XIP_SSI_CTRLR0_SPI_FRF_STD << XIP_SSI_CTRLR0_SPI_FRF_Pos) |
(XIP_SSI_CTRLR0_TMOD_EEPROM_READ << XIP_SSI_CTRLR0_TMOD_Pos) |
((32-1) << XIP_SSI_CTRLR0_DFS_32_Pos);
XIP_SSI->CTRLR1 = (0 << XIP_SSI_CTRLR1_NDF_Pos);
XIP_SSI->SPI_CTRLR0 = (0x03/*READ_DATA*/ << XIP_SSI_SPI_CTRLR0_XIP_CMD_Pos) |
((24 / 4) << XIP_SSI_SPI_CTRLR0_ADDR_L_Pos) |
(XIP_SSI_SPI_CTRLR0_INST_L_8B << XIP_SSI_SPI_CTRLR0_INST_L_Pos) |
(XIP_SSI_SPI_CTRLR0_TRANS_TYPE_1C1A << XIP_SSI_SPI_CTRLR0_TRANS_TYPE_Pos);
XIP_SSI->SSIENR = XIP_SSI_SSIENR_SSI_EN_Msk;
uint32_t *src = &_text_start;
uint32_t *dst = &_text;
while (dst < &_edata)
*dst++ = *src++;
dst = &_bss;
while (dst < &_ebss)
*dst++ = 0;
SCB->VTOR = (uint32_t)vectors;
asm (R"asm(
msr msp, %[sp]
bx %[reset]
)asm"
:: [sp] "r" (&_stack_top), [reset] "r" (main)
);
__builtin_unreachable();
}

3
platform/rp2040/tools/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
bin2uf2
bin2uf2.exe

View File

@ -0,0 +1,6 @@
all: bin2uf2.c
gcc -W -Wall -Wextra -O3 -std=gnu11 bin2uf2.c -o bin2uf2
clean:
rm -rf bin2uf2 bin2uf2.exe

View File

@ -0,0 +1,245 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
/*- Definitions -------------------------------------------------------------*/
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define MAX_FILE_SIZE (16*1024*1024)
#define UF2_MAGIC_START_0 0x0a324655
#define UF2_MAGIC_START_1 0x9e5d5157
#define UF2_MAGIC_END 0x0ab16f30
#define UF2_FLAG_FAMILY_ID 0x00002000
#define UF2_FAMILY_ID_RP2040 0xe48bff56
#define UF2_BLOCK_SIZE 256
#define FLASH_START 0x10000000
#define BL2_SIZE 256
/*- Definitions -------------------------------------------------------------*/
typedef struct
{
uint32_t magic_start_0;
uint32_t magic_start_1;
uint32_t flags;
uint32_t target_addr;
uint32_t payload_size;
uint32_t block_no;
uint32_t num_blocks;
uint32_t family_id;
uint8_t data[476];
uint32_t magic_end;
} UF2Block;
/*- Variables ---------------------------------------------------------------*/
static const struct option long_options[] =
{
{ "help", no_argument, 0, 'h' },
{ "update", no_argument, 0, 'u' },
{ "input", required_argument, 0, 'i' },
{ "output", required_argument, 0, 'o' },
{ 0, 0, 0, 0 }
};
static const char *short_options = "hui:o:";
static bool g_update = false;
static char *g_input = NULL;
static char *g_output = NULL;
static uint32_t crc32_tab[256];
static uint8_t g_data[MAX_FILE_SIZE];
static int g_size = 0;
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
static void crc32_tab_gen(void)
{
for (int i = 0; i < 256; i++)
{
uint32_t value = i << 24;
for (int j = 0; j < 8; j++)
{
if (value & (1 << 31))
value = (value << 1) ^ 0x4c11db7ul;
else
value = value << 1;
}
crc32_tab[i] = value;
}
}
//-----------------------------------------------------------------------------
static uint32_t crc32(uint8_t *data, int size)
{
uint32_t crc = 0xffffffff;
for (int i = 0; i < size; i++)
crc = crc32_tab[((crc >> 24) & 0xff) ^ data[i]] ^ (crc << 8);
return crc;
}
//-----------------------------------------------------------------------------
static void check(bool cond, char *fmt, ...)
{
if (!cond)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}
}
//-----------------------------------------------------------------------------
static void perror_exit(char *text)
{
perror(text);
exit(1);
}
//-----------------------------------------------------------------------------
static void print_help(char *name)
{
printf("Usage: %s [options]\n", name);
printf("Options:\n");
printf(" -h, --help print this help message and exit\n");
printf(" -u, --update generate raw binary file with an updated CRC\n");
printf(" -i, --input <name> input file name\n");
printf(" -o, --output <name> output file name\n");
exit(0);
}
//-----------------------------------------------------------------------------
static void parse_command_line(int argc, char **argv)
{
int option_index = 0;
int c;
while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1)
{
switch (c)
{
case 'h': print_help(argv[0]); break;
case 'u': g_update = true; break;
case 'i': g_input = optarg; break;
case 'o': g_output = optarg; break;
default: exit(1); break;
}
}
check(optind >= argc, "malformed command line, use '-h' for more information");
}
//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
int fd;
uint32_t crc;
crc32_tab_gen();
parse_command_line(argc, argv);
check(NULL != g_input, "input file name is not specified");
check(NULL != g_output, "output file name is not specified");
memset(g_data, 0xff, sizeof(g_data));
fd = open(g_input, O_RDONLY | O_BINARY);
if (fd < 0)
perror_exit("open()");
g_size = read(fd, g_data, sizeof(g_data));
if (g_size < 0)
perror_exit("read()");
check(g_size < (int)sizeof(g_data), "input file is too big");
close(fd);
while ((g_size % UF2_BLOCK_SIZE) != 0)
g_size++;
crc = crc32(g_data, BL2_SIZE-4);
g_data[BL2_SIZE-4] = (crc >> 0);
g_data[BL2_SIZE-3] = (crc >> 8);
g_data[BL2_SIZE-2] = (crc >> 16);
g_data[BL2_SIZE-1] = (crc >> 24);
fd = open(g_output, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0644);
if (fd < 0)
perror_exit("open()");
if (g_update)
{
if (write(fd, g_data, g_size) < 0)
perror_exit("write()");
}
else
{
UF2Block block;
uint32_t offs = 0;
uint32_t addr = FLASH_START;
int n_blocks = g_size / UF2_BLOCK_SIZE;
block.magic_start_0 = UF2_MAGIC_START_0;
block.magic_start_1 = UF2_MAGIC_START_1;
block.flags = UF2_FLAG_FAMILY_ID;
block.payload_size = UF2_BLOCK_SIZE;
block.num_blocks = n_blocks;
block.family_id = UF2_FAMILY_ID_RP2040;
block.magic_end = UF2_MAGIC_END;
memset(block.data, 0, sizeof(block.data));
for (int i = 0; i < n_blocks; i++)
{
block.target_addr = addr;
block.block_no = i;
memcpy(block.data, &g_data[offs], UF2_BLOCK_SIZE);
if (write(fd, &block, sizeof(UF2Block)) < 0)
perror_exit("write()");
addr += UF2_BLOCK_SIZE;
offs += UF2_BLOCK_SIZE;
}
}
close(fd);
return 0;
}

224
platform/rp2040/uart.c Normal file
View File

@ -0,0 +1,224 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rp2040.h"
#include "hal_config.h"
#include "uart.h"
#include "usb_cdc.h"
/*- Definitions -------------------------------------------------------------*/
#define UART_BUF_SIZE 256
/*- Types ------------------------------------------------------------------*/
typedef struct
{
int wr;
int rd;
uint16_t data[UART_BUF_SIZE];
} fifo_buffer_t;
/*- Variables --------------------------------------------------------------*/
static volatile fifo_buffer_t uart_rx_fifo;
static volatile fifo_buffer_t uart_tx_fifo;
static volatile bool uart_fifo_overflow = false;
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
void uart_init(usb_cdc_line_coding_t *line_coding)
{
int wlen, parity, stop, baud;
RESETS_SET->RESET = UART_RESET_MASK;
RESETS_CLR->RESET = UART_RESET_MASK;
while (0 == (RESETS->RESET_DONE & UART_RESET_MASK));
uart_tx_fifo.wr = 0;
uart_tx_fifo.rd = 0;
uart_rx_fifo.wr = 0;
uart_rx_fifo.rd = 0;
uart_fifo_overflow = false;
if (USB_CDC_5_DATA_BITS == line_coding->bDataBits)
wlen = 0;
else if (USB_CDC_6_DATA_BITS == line_coding->bDataBits)
wlen = 1;
else if (USB_CDC_7_DATA_BITS == line_coding->bDataBits)
wlen = 2;
else if (USB_CDC_8_DATA_BITS == line_coding->bDataBits)
wlen = 3;
else
wlen = 3;
if (USB_CDC_NO_PARITY == line_coding->bParityType)
parity = 0;
else if (USB_CDC_ODD_PARITY == line_coding->bParityType)
parity = UART0_UARTLCR_H_PEN_Msk;
else if (USB_CDC_EVEN_PARITY == line_coding->bParityType)
parity = UART0_UARTLCR_H_PEN_Msk | UART0_UARTLCR_H_EPS_Msk;
else if (USB_CDC_MARK_PARITY == line_coding->bParityType)
parity = UART0_UARTLCR_H_PEN_Msk | UART0_UARTLCR_H_SPS_Msk;
else if (USB_CDC_SPACE_PARITY == line_coding->bParityType)
parity = UART0_UARTLCR_H_PEN_Msk | UART0_UARTLCR_H_SPS_Msk | UART0_UARTLCR_H_EPS_Msk;
else
parity = 0;
if (USB_CDC_1_STOP_BIT == line_coding->bCharFormat)
stop = 0;
else
stop = UART0_UARTLCR_H_STP2_Msk;
baud = (UART_CLOCK * 4) / line_coding->dwDTERate;
UART_PER->UARTIFLS = (3 << UART0_UARTIFLS_RXIFLSEL_Pos) | (0 << UART0_UARTIFLS_TXIFLSEL_Pos);
UART_PER->UARTIBRD = baud / 64;
UART_PER->UARTFBRD = baud % 64;
UART_PER->UARTLCR_H = (wlen << UART0_UARTLCR_H_WLEN_Pos) | parity | stop | UART0_UARTLCR_H_FEN_Msk;
UART_PER->UARTIMSC = UART0_UARTIMSC_RXIM_Msk | UART0_UARTIMSC_RTIM_Msk | UART0_UARTIMSC_TXIM_Msk;
HAL_GPIO_UART_TX_init();
HAL_GPIO_UART_TX_pullup();
HAL_GPIO_UART_RX_init();
HAL_GPIO_UART_RX_pullup();
UART_PER->UARTCR = UART0_UARTCR_UARTEN_Msk | UART0_UARTCR_RXE_Msk | UART0_UARTCR_TXE_Msk;
NVIC_EnableIRQ(UART_IRQ_INDEX);
}
//-----------------------------------------------------------------------------
void uart_close(void)
{
RESETS_SET->RESET = UART_RESET_MASK;
}
//-----------------------------------------------------------------------------
bool uart_write_byte(int byte)
{
int wr = (uart_tx_fifo.wr + 1) % UART_BUF_SIZE;
bool res = false;
NVIC_DisableIRQ(UART_IRQ_INDEX);
if (uart_tx_fifo.rd == uart_tx_fifo.wr && !UART_PER->UARTFR_b.TXFF)
{
UART_PER->UARTDR = byte;
res = true;
}
else if (wr != uart_tx_fifo.rd)
{
uart_tx_fifo.data[uart_tx_fifo.wr] = byte;
uart_tx_fifo.wr = wr;
res = true;
}
NVIC_EnableIRQ(UART_IRQ_INDEX);
return res;
}
//-----------------------------------------------------------------------------
bool uart_read_byte(int *byte)
{
bool res = false;
NVIC_DisableIRQ(UART_IRQ_INDEX);
if (uart_fifo_overflow)
{
*byte = (USB_CDC_SERIAL_STATE_OVERRUN << 8);
uart_fifo_overflow = false;
res = true;
}
else if (uart_rx_fifo.rd != uart_rx_fifo.wr)
{
*byte = uart_rx_fifo.data[uart_rx_fifo.rd];
uart_rx_fifo.rd = (uart_rx_fifo.rd + 1) % UART_BUF_SIZE;
res = true;
}
NVIC_EnableIRQ(UART_IRQ_INDEX);
return res;
}
//-----------------------------------------------------------------------------
void uart_set_break(bool brk)
{
if (brk)
UART_PER->UARTLCR_H |= UART0_UARTLCR_H_BRK_Msk;
else
UART_PER->UARTLCR_H &= ~UART0_UARTLCR_H_BRK_Msk;
}
//-----------------------------------------------------------------------------
void UART_IRQ_HANDLER(void)
{
int flags = UART_PER->UARTMIS;
if (flags & (UART0_UARTIMSC_RXIM_Msk | UART0_UARTIMSC_RTIM_Msk))
{
while (!UART_PER->UARTFR_b.RXFE)
{
int byte = UART_PER->UARTDR;
int wr = (uart_rx_fifo.wr + 1) % UART_BUF_SIZE;
int state = 0;
if (byte & UART0_UARTDR_BE_Msk)
{
state |= USB_CDC_SERIAL_STATE_BREAK;
byte &= ~(UART0_UARTDR_PE_Msk | UART0_UARTDR_FE_Msk);
}
if (byte & UART0_UARTDR_PE_Msk)
state |= USB_CDC_SERIAL_STATE_PARITY;
if (byte & UART0_UARTDR_FE_Msk)
state |= USB_CDC_SERIAL_STATE_FRAMING;
if (byte & UART0_UARTDR_OE_Msk)
state |= USB_CDC_SERIAL_STATE_OVERRUN;
byte = (state << 8) | (byte & UART0_UARTDR_DATA_Msk);
if (wr == uart_rx_fifo.rd)
{
uart_fifo_overflow = true;
break;
}
else
{
uart_rx_fifo.data[uart_rx_fifo.wr] = byte;
uart_rx_fifo.wr = wr;
}
}
}
if (flags & UART0_UARTIMSC_TXIM_Msk)
{
UART_PER->UARTICR = UART0_UARTICR_TXIC_Msk;
while (!UART_PER->UARTFR_b.TXFF)
{
if (uart_tx_fifo.rd == uart_tx_fifo.wr)
break;
UART_PER->UARTDR = uart_tx_fifo.data[uart_tx_fifo.rd];
uart_tx_fifo.rd = (uart_tx_fifo.rd + 1) % UART_BUF_SIZE;
}
}
}

20
platform/rp2040/uart.h Normal file
View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _UART_H_
#define _UART_H_
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "usb_cdc.h"
/*- Prototypes --------------------------------------------------------------*/
void uart_init(usb_cdc_line_coding_t *line_coding);
void uart_close(void);
bool uart_write_byte(int byte);
bool uart_read_byte(int *byte);
void uart_set_break(bool brk);
#endif // _UART_H_

368
platform/rp2040/usb.c Normal file
View File

@ -0,0 +1,368 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <string.h>
#include <stdbool.h>
#include <stdalign.h>
#include "rp2040.h"
#include "utils.h"
#include "usb.h"
#include "usb_std.h"
#include "usb_descriptors.h"
/*- Definitions -------------------------------------------------------------*/
#define USB_DPRAM_SIZE 4096
#define USB_DPRAM ((usb_dpram_t *)USBCTRL_DPRAM_BASE)
#define USB_DPRAM_FIXED_SIZE 0x100
#define USB_DPRAM_BUF_OFFSET (USB_DPRAM_FIXED_SIZE + USB_CTRL_EP_SIZE*2)
/*- Types -------------------------------------------------------------------*/
typedef struct
{
__IOM uint8_t SETUP[8];
struct // Starts with EP1
{
__IOM uint32_t IN;
__IOM uint32_t OUT;
} EP_CTRL[USB_EP_NUM-1];
struct // Starts with EP0
{
__IOM uint32_t IN;
__IOM uint32_t OUT;
} EP_BUF_CTRL[USB_EP_NUM];
__IOM uint8_t EP0_BUF[USB_CTRL_EP_SIZE];
__IOM uint8_t DUMMY[USB_CTRL_EP_SIZE];
} usb_dpram_t;
typedef struct
{
int in_pid;
volatile uint8_t *in_buf;
int out_pid;
volatile uint8_t *out_buf;
uint8_t *out_data;
} usb_ep_t;
/*- Variables ---------------------------------------------------------------*/
static int usb_ep_buf_ptr = 0;
static usb_ep_t usb_ep[USB_EP_NUM];
static void (*usb_control_recv_callback)(uint8_t *data, int size);
/*- Prototypes --------------------------------------------------------------*/
static void usb_reset_endpoints(void);
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
void usb_hw_init(void)
{
RESETS_CLR->RESET = RESETS_RESET_usbctrl_Msk;
while (0 == RESETS->RESET_DONE_b.usbctrl);
memset(USBCTRL_DPRAM, 0, USB_DPRAM_SIZE);
USBCTRL_REGS->USB_MUXING = USBCTRL_REGS_USB_MUXING_TO_PHY_Msk |
USBCTRL_REGS_USB_MUXING_SOFTCON_Msk;
USBCTRL_REGS->USB_PWR = USBCTRL_REGS_USB_PWR_VBUS_DETECT_Msk |
USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN_Msk;
USBCTRL_REGS->MAIN_CTRL = USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN_Msk;
USBCTRL_REGS->SIE_CTRL = USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk;
USBCTRL_REGS->ADDR_ENDP = 0;
USBCTRL_REGS->INTE = USBCTRL_REGS_INTE_BUFF_STATUS_Msk |
USBCTRL_REGS_INTE_SETUP_REQ_Msk | USBCTRL_REGS_INTE_BUS_RESET_Msk;
usb_reset_endpoints();
usb_attach();
}
//-----------------------------------------------------------------------------
void usb_attach(void)
{
USBCTRL_REGS_SET->SIE_CTRL = USBCTRL_REGS_SIE_CTRL_PULLUP_EN_Msk;
}
//-----------------------------------------------------------------------------
void usb_detach(void)
{
USBCTRL_REGS_CLR->SIE_CTRL = USBCTRL_REGS_SIE_CTRL_PULLUP_EN_Msk;
}
//-----------------------------------------------------------------------------
static void usb_reset_endpoints(void)
{
for (int i = 0; i < USB_EP_NUM-1; i++)
{
USB_DPRAM->EP_CTRL[i].IN = 0;
USB_DPRAM->EP_CTRL[i].OUT = 0;
}
memset(&usb_ep, 0, sizeof(usb_ep));
usb_ep_buf_ptr = USB_DPRAM_BUF_OFFSET;
}
//-----------------------------------------------------------------------------
void usb_configure_endpoint(usb_endpoint_descriptor_t *desc)
{
int ep, dir, type, size;
ep = desc->bEndpointAddress & USB_INDEX_MASK;
dir = desc->bEndpointAddress & USB_DIRECTION_MASK;
type = desc->bmAttributes & 0x03;
size = desc->wMaxPacketSize & 0x3ff;
if (size <= 64)
size = 64;
else if (size <= 128)
size = 128;
else if (size <= 256)
size = 256;
else if (size <= 512)
size = 512;
else
size = 1024;
if (USB_IN_ENDPOINT == dir)
{
usb_ep[ep].in_buf = (volatile uint8_t *)(USBCTRL_DPRAM_BASE + usb_ep_buf_ptr);
USB_DPRAM->EP_CTRL[ep-1].IN = USBCTRL_DPRAM_EP1_IN_CONTROL_ENABLE_Msk |
USBCTRL_DPRAM_EP1_IN_CONTROL_INTERRUPT_PER_BUFF_Msk |
(type << USBCTRL_DPRAM_EP1_IN_CONTROL_ENDPOINT_TYPE_Pos) |
(usb_ep_buf_ptr << USBCTRL_DPRAM_EP1_IN_CONTROL_BUFFER_ADDRESS_Pos);
}
else
{
usb_ep[ep].out_buf = (volatile uint8_t *)(USBCTRL_DPRAM_BASE + usb_ep_buf_ptr);
USB_DPRAM->EP_CTRL[ep-1].OUT = USBCTRL_DPRAM_EP1_OUT_CONTROL_ENABLE_Msk |
USBCTRL_DPRAM_EP1_OUT_CONTROL_INTERRUPT_PER_BUFF_Msk |
(type << USBCTRL_DPRAM_EP1_OUT_CONTROL_ENDPOINT_TYPE_Pos) |
(usb_ep_buf_ptr << USBCTRL_DPRAM_EP1_OUT_CONTROL_BUFFER_ADDRESS_Pos);
}
usb_ep_buf_ptr += size;
}
//-----------------------------------------------------------------------------
bool usb_endpoint_configured(int ep, int dir)
{
if (USB_IN_ENDPOINT == dir)
return (USB_DPRAM->EP_CTRL[ep-1].IN & USBCTRL_DPRAM_EP1_IN_CONTROL_ENABLE_Msk) != 0;
else
return (USB_DPRAM->EP_CTRL[ep-1].OUT & USBCTRL_DPRAM_EP1_OUT_CONTROL_ENABLE_Msk) != 0;
}
//-----------------------------------------------------------------------------
int usb_endpoint_get_status(int ep, int dir)
{
if (USB_IN_ENDPOINT == dir)
return (USB_DPRAM->EP_BUF_CTRL[ep].IN & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk) != 0;
else
return (USB_DPRAM->EP_BUF_CTRL[ep].OUT & USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_STALL_Msk) != 0;
}
//-----------------------------------------------------------------------------
void usb_endpoint_set_feature(int ep, int dir)
{
if (USB_IN_ENDPOINT == dir)
USB_DPRAM->EP_BUF_CTRL[ep].IN = USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk;
else
USB_DPRAM->EP_BUF_CTRL[ep].OUT = USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_STALL_Msk;
}
//-----------------------------------------------------------------------------
void usb_endpoint_clear_feature(int ep, int dir)
{
if (USB_IN_ENDPOINT == dir)
{
usb_ep[ep].in_pid = 0;
USB_DPRAM->EP_BUF_CTRL[ep].IN &= ~USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk;
}
else
{
usb_ep[0].out_pid = 0;
USB_DPRAM->EP_BUF_CTRL[ep].OUT &= ~USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_STALL_Msk;
}
}
//-----------------------------------------------------------------------------
void usb_set_address(int address)
{
USBCTRL_REGS->ADDR_ENDP = address;
}
//-----------------------------------------------------------------------------
static void usb_start_in_transfer(int ep, int size)
{
uint32_t v = size | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk |
(usb_ep[ep].in_pid ? USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_PID_0_Msk : 0);
usb_ep[ep].in_pid ^= 1;
USB_DPRAM->EP_BUF_CTRL[ep].IN = v;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
USB_DPRAM->EP_BUF_CTRL[ep].IN = v | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk;
}
//-----------------------------------------------------------------------------
static void usb_start_out_transfer(int ep, int size)
{
uint32_t v = size | (usb_ep[ep].out_pid ? USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_PID_0_Msk : 0);
usb_ep[ep].out_pid ^= 1;
USB_DPRAM->EP_BUF_CTRL[ep].OUT = v;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
USB_DPRAM->EP_BUF_CTRL[ep].OUT = v | USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_AVAILABLE_0_Msk;
}
//-----------------------------------------------------------------------------
void usb_send(int ep, uint8_t *data, int size)
{
for (int i = 0; i < size; i++)
usb_ep[ep].in_buf[i] = data[i];
usb_start_in_transfer(ep, size);
}
//-----------------------------------------------------------------------------
void usb_recv(int ep, uint8_t *data, int size)
{
usb_ep[ep].out_data = data;
usb_start_out_transfer(ep, size);
}
//-----------------------------------------------------------------------------
void usb_control_send_zlp(void)
{
usb_start_in_transfer(0, 0);
while (0 == (USBCTRL_REGS->BUFF_STATUS & USBCTRL_REGS_BUFF_STATUS_EP0_IN_Msk));
USBCTRL_REGS->BUFF_STATUS = USBCTRL_REGS_BUFF_STATUS_EP0_IN_Msk;
}
//-----------------------------------------------------------------------------
void usb_control_stall(void)
{
USBCTRL_REGS->EP_STALL_ARM = USBCTRL_REGS_EP_STALL_ARM_EP0_IN_Msk;
USB_DPRAM->EP_BUF_CTRL[0].IN = USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk;
}
//-----------------------------------------------------------------------------
void usb_control_send(uint8_t *data, int size)
{
while (size)
{
int transfer_size = LIMIT(size, usb_device_descriptor.bMaxPacketSize0);
for (int i = 0; i < transfer_size; i++)
usb_ep[0].in_buf[i] = data[i];
usb_start_in_transfer(0, transfer_size);
while (0 == (USBCTRL_REGS->BUFF_STATUS & USBCTRL_REGS_BUFF_STATUS_EP0_IN_Msk));
USBCTRL_REGS->BUFF_STATUS = USBCTRL_REGS_BUFF_STATUS_EP0_IN_Msk;
size -= transfer_size;
data += transfer_size;
}
usb_start_out_transfer(0, USB_CTRL_EP_SIZE);
}
//-----------------------------------------------------------------------------
void usb_control_recv(void (*callback)(uint8_t *data, int size))
{
usb_control_recv_callback = callback;
usb_start_out_transfer(0, USB_CTRL_EP_SIZE);
}
//-----------------------------------------------------------------------------
void usb_task(void)
{
uint32_t status = USBCTRL_REGS->INTS;
uint32_t flags;
if (status & USBCTRL_REGS_INTS_BUS_RESET_Msk)
{
USBCTRL_REGS_CLR->SIE_STATUS = USBCTRL_REGS_SIE_STATUS_BUS_RESET_Msk;
USBCTRL_REGS->ADDR_ENDP = 0;
usb_reset_endpoints();
usb_ep[0].in_buf = (volatile uint8_t *)(USBCTRL_DPRAM_BASE + USB_DPRAM_FIXED_SIZE);
usb_ep[0].out_buf = (volatile uint8_t *)(USBCTRL_DPRAM_BASE + USB_DPRAM_FIXED_SIZE);
}
if (status & USBCTRL_REGS_INTS_SETUP_REQ_Msk)
{
usb_request_t *request = (usb_request_t *)USBCTRL_DPRAM;
usb_ep[0].in_pid = 1;
usb_ep[0].out_pid = 1;
USBCTRL_REGS_CLR->SIE_STATUS = USBCTRL_REGS_SIE_STATUS_SETUP_REC_Msk;
if (!usb_handle_standard_request(request))
usb_control_stall();
}
if (status & USBCTRL_REGS_INTS_BUFF_STATUS_Msk)
{
status = USBCTRL_REGS->BUFF_STATUS;
if (status & USBCTRL_REGS_BUFF_STATUS_EP0_OUT_Msk)
{
int size = USB_DPRAM->EP_BUF_CTRL[0].OUT & USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0_Msk;
if (usb_control_recv_callback)
{
usb_control_recv_callback((uint8_t *)usb_ep[0].out_buf, size);
usb_control_recv_callback = NULL;
usb_control_send_zlp();
}
}
flags = status >> 2;
for (int ep = 1; ep < USB_EP_NUM && flags > 0; ep++)
{
if (flags & 1) // IN
{
usb_send_callback(ep);
}
if (flags & 2) // OUT
{
int size = USB_DPRAM->EP_BUF_CTRL[ep].OUT & USBCTRL_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0_Msk;
for (int i = 0; i < size; i++)
usb_ep[ep].out_data[i] = usb_ep[ep].out_buf[i];
usb_recv_callback(ep, size);
}
flags >>= 2;
}
USBCTRL_REGS->BUFF_STATUS = status;
}
}

36
platform/rp2040/usb.h Normal file
View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2016-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _USB_H_
#define _USB_H_
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "usb_descriptors.h"
/*- Definitions -------------------------------------------------------------*/
#define USB_EP_NUM 16
/*- Prototypes --------------------------------------------------------------*/
void usb_hw_init(void);
void usb_attach(void);
void usb_detach(void);
void usb_configure_endpoint(usb_endpoint_descriptor_t *ep_desc);
bool usb_endpoint_configured(int ep, int dir);
int usb_endpoint_get_status(int ep, int dir);
void usb_endpoint_set_feature(int ep, int dir);
void usb_endpoint_clear_feature(int ep, int dir);
void usb_set_address(int address);
void usb_send(int ep, uint8_t *data, int size);
void usb_recv(int ep, uint8_t *data, int size);
void usb_control_send_zlp(void);
void usb_control_stall(void);
void usb_control_send(uint8_t *data, int size);
void usb_control_recv(void (*callback)(uint8_t *data, int size));
void usb_task(void);
void usb_configuration_callback(int config);
#endif // _USB_H_

198
platform/rp2040/usb_cdc.c Normal file
View File

@ -0,0 +1,198 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2017-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdbool.h>
#include <stdalign.h>
#include <string.h>
#include "utils.h"
#include "usb.h"
#include "usb_std.h"
#include "usb_cdc.h"
#include "usb_descriptors.h"
/*- Definitions -------------------------------------------------------------*/
#define ONE_SHOT_STATES (USB_CDC_SERIAL_STATE_BREAK | USB_CDC_SERIAL_STATE_RING | \
USB_CDC_SERIAL_STATE_FRAMING | USB_CDC_SERIAL_STATE_PARITY | USB_CDC_SERIAL_STATE_OVERRUN)
/*- Prototypes --------------------------------------------------------------*/
static void usb_cdc_send_state_notify(void);
static void usb_cdc_ep_comm_callback(int size);
static void usb_cdc_ep_send_callback(int size);
static void usb_cdc_ep_recv_callback(int size);
/*- Variables ---------------------------------------------------------------*/
static usb_cdc_line_coding_t usb_cdc_line_coding =
{
.dwDTERate = 115200,
.bCharFormat = USB_CDC_1_STOP_BIT,
.bParityType = USB_CDC_NO_PARITY,
.bDataBits = USB_CDC_8_DATA_BITS,
};
static alignas(4) usb_cdc_notify_serial_state_t usb_cdc_notify_message;
static int usb_cdc_serial_state;
static bool usb_cdc_comm_busy;
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
void usb_cdc_init(void)
{
usb_set_callback(USB_CDC_EP_COMM, usb_cdc_ep_comm_callback);
usb_set_callback(USB_CDC_EP_SEND, usb_cdc_ep_send_callback);
usb_set_callback(USB_CDC_EP_RECV, usb_cdc_ep_recv_callback);
usb_cdc_notify_message.request.bmRequestType = USB_IN_TRANSFER |
USB_INTERFACE_RECIPIENT | USB_CLASS_REQUEST;
usb_cdc_notify_message.request.bRequest = USB_CDC_NOTIFY_SERIAL_STATE;
usb_cdc_notify_message.request.wValue = 0;
usb_cdc_notify_message.request.wIndex = 0;
usb_cdc_notify_message.request.wLength = sizeof(uint16_t);
usb_cdc_notify_message.value = 0;
usb_cdc_serial_state = 0;
usb_cdc_comm_busy = false;
usb_cdc_line_coding_updated(&usb_cdc_line_coding);
}
//-----------------------------------------------------------------------------
void usb_cdc_send(uint8_t *data, int size)
{
usb_send(USB_CDC_EP_SEND, data, size);
}
//-----------------------------------------------------------------------------
void usb_cdc_recv(uint8_t *data, int size)
{
usb_recv(USB_CDC_EP_RECV, data, size);
}
//-----------------------------------------------------------------------------
void usb_cdc_set_state(int mask)
{
usb_cdc_serial_state |= mask;
usb_cdc_send_state_notify();
}
//-----------------------------------------------------------------------------
void usb_cdc_clear_state(int mask)
{
usb_cdc_serial_state &= ~mask;
usb_cdc_send_state_notify();
}
//-----------------------------------------------------------------------------
usb_cdc_line_coding_t *usb_cdc_get_line_coding(void)
{
return &usb_cdc_line_coding;
}
//-----------------------------------------------------------------------------
static void usb_cdc_send_state_notify(void)
{
if (usb_cdc_comm_busy)
return;
if (usb_cdc_serial_state != usb_cdc_notify_message.value)
{
usb_cdc_comm_busy = true;
usb_cdc_notify_message.value = usb_cdc_serial_state;
usb_cdc_serial_state &= ~ONE_SHOT_STATES;
usb_send(USB_CDC_EP_COMM, (uint8_t *)&usb_cdc_notify_message, sizeof(usb_cdc_notify_serial_state_t));
}
}
//-----------------------------------------------------------------------------
static void usb_cdc_ep_comm_callback(int size)
{
usb_cdc_comm_busy = false;
usb_cdc_notify_message.value &= ~ONE_SHOT_STATES;
usb_cdc_send_state_notify();
(void)size;
}
//-----------------------------------------------------------------------------
static void usb_cdc_ep_send_callback(int size)
{
usb_cdc_send_callback();
(void)size;
}
//-----------------------------------------------------------------------------
static void usb_cdc_ep_recv_callback(int size)
{
usb_cdc_recv_callback(size);
}
//-----------------------------------------------------------------------------
static void usb_cdc_set_line_coding_handler(uint8_t *data, int size)
{
usb_cdc_line_coding_t *line_coding = (usb_cdc_line_coding_t *)data;
if (sizeof(usb_cdc_line_coding_t) != size)
return;
usb_cdc_line_coding = *line_coding;
usb_cdc_line_coding_updated(&usb_cdc_line_coding);
}
//-----------------------------------------------------------------------------
bool usb_cdc_handle_request(usb_request_t *request)
{
int length = request->wLength;
switch ((request->bRequest << 8) | request->bmRequestType)
{
case USB_CMD(OUT, INTERFACE, CLASS, CDC_SET_LINE_CODING):
{
length = LIMIT(length, sizeof(usb_cdc_line_coding_t));
usb_control_recv(usb_cdc_set_line_coding_handler);
} break;
case USB_CMD(IN, INTERFACE, CLASS, CDC_GET_LINE_CODING):
{
length = LIMIT(length, sizeof(usb_cdc_line_coding_t));
usb_control_send((uint8_t *)&usb_cdc_line_coding, length);
} break;
case USB_CMD(OUT, INTERFACE, CLASS, CDC_SET_CONTROL_LINE_STATE):
{
usb_cdc_control_line_state_update(request->wValue);
usb_control_send_zlp();
} break;
case USB_CMD(OUT, INTERFACE, CLASS, CDC_SEND_BREAK):
{
usb_cdc_send_break(request->wValue);
usb_control_send_zlp();
} break;
default:
return false;
}
return true;
}
//-----------------------------------------------------------------------------
WEAK void usb_cdc_control_line_state_update(int line_state)
{
(void)line_state;
}
//-----------------------------------------------------------------------------
WEAK void usb_cdc_send_break(int duration)
{
(void)duration;
}

211
platform/rp2040/usb_cdc.h Normal file
View File

@ -0,0 +1,211 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2017-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _USB_CDC_H_
#define _USB_CDC_H_
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "utils.h"
#include "usb_std.h"
/*- Definitions -------------------------------------------------------------*/
enum
{
USB_CDC_SEND_ENCAPSULATED_COMMAND = 0x00,
USB_CDC_GET_ENCAPSULATED_RESPONSE = 0x01,
USB_CDC_SET_COMM_FEATURE = 0x02,
USB_CDC_GET_COMM_FEATURE = 0x03,
USB_CDC_CLEAR_COMM_FEATURE = 0x04,
USB_CDC_SET_AUX_LINE_STATE = 0x10,
USB_CDC_SET_HOOK_STATE = 0x11,
USB_CDC_PULSE_SETUP = 0x12,
USB_CDC_SEND_PULSE = 0x13,
USB_CDC_SET_PULSE_TIME = 0x14,
USB_CDC_RING_AUX_JACK = 0x15,
USB_CDC_SET_LINE_CODING = 0x20,
USB_CDC_GET_LINE_CODING = 0x21,
USB_CDC_SET_CONTROL_LINE_STATE = 0x22,
USB_CDC_SEND_BREAK = 0x23,
USB_CDC_SET_RINGER_PARMS = 0x30,
USB_CDC_GET_RINGER_PARMS = 0x31,
USB_CDC_SET_OPERATION_PARMS = 0x32,
USB_CDC_GET_OPERATION_PARMS = 0x33,
USB_CDC_SET_LINE_PARMS = 0x34,
USB_CDC_GET_LINE_PARMS = 0x35,
USB_CDC_DIAL_DIGITS = 0x36,
USB_CDC_SET_UNIT_PARAMETER = 0x37,
USB_CDC_GET_UNIT_PARAMETER = 0x38,
USB_CDC_CLEAR_UNIT_PARAMETER = 0x39,
USB_CDC_GET_PROFILE = 0x3a,
USB_CDC_NOTIFY_RING_DETECT = 0x09,
USB_CDC_NOTIFY_SERIAL_STATE = 0x20,
USB_CDC_NOTIFY_CALL_STATE_CHANGE = 0x28,
USB_CDC_NOTIFY_LINE_STATE_CHANGE = 0x29,
};
enum
{
USB_CDC_1_STOP_BIT = 0,
USB_CDC_1_5_STOP_BITS = 1,
USB_CDC_2_STOP_BITS = 2,
};
enum
{
USB_CDC_NO_PARITY = 0,
USB_CDC_ODD_PARITY = 1,
USB_CDC_EVEN_PARITY = 2,
USB_CDC_MARK_PARITY = 3,
USB_CDC_SPACE_PARITY = 4,
};
enum
{
USB_CDC_5_DATA_BITS = 5,
USB_CDC_6_DATA_BITS = 6,
USB_CDC_7_DATA_BITS = 7,
USB_CDC_8_DATA_BITS = 8,
USB_CDC_16_DATA_BITS = 16,
};
enum
{
USB_CDC_DEVICE_CLASS = 2, // USB Communication Device Class
USB_CDC_COMM_CLASS = 2, // CDC Communication Class Interface
USB_CDC_DATA_CLASS = 10, // CDC Data Class Interface
};
enum
{
USB_CDC_NO_SUBCLASS = 0,
USB_CDC_DLCM_SUBCLASS = 1, // Direct Line Control Model
USB_CDC_ACM_SUBCLASS = 2, // Abstract Control Model
USB_CDC_TCM_SUBCLASS = 3, // Telephone Control Model
USB_CDC_MCCM_SUBCLASS = 4, // Multi-Channel Control Model
USB_CDC_CCM_SUBCLASS = 5, // CAPI Control Model
USB_CDC_ETH_SUBCLASS = 6, // Ethernet Networking Control Model
USB_CDC_ATM_SUBCLASS = 7, // ATM Networking Control Model
};
enum
{
USB_CDC_HEADER_SUBTYPE = 0, // Header Functional Descriptor
USB_CDC_CALL_MGMT_SUBTYPE = 1, // Call Management
USB_CDC_ACM_SUBTYPE = 2, // Abstract Control Management
USB_CDC_UNION_SUBTYPE = 6, // Union Functional Descriptor
};
// USB CDC Call Management Capabilities
enum
{
USB_CDC_CALL_MGMT_SUPPORTED = (1 << 0),
USB_CDC_CALL_MGMT_OVER_DCI = (1 << 1),
};
// USB CDC ACM Capabilities
enum
{
// Device supports the request combination of Set_Comm_Feature,
// Clear_Comm_Feature, and Get_Comm_Feature.
USB_CDC_ACM_SUPPORT_FEATURE_REQUESTS = (1 << 0),
// Device supports the request combination of Set_Line_Coding, Set_Control_Line_State,
// Get_Line_Coding, and the notification Serial_State.
USB_CDC_ACM_SUPPORT_LINE_REQUESTS = (1 << 1),
// Device supports the request Send_Break.
USB_CDC_ACM_SUPPORT_SENDBREAK_REQUESTS = (1 << 2),
// Device supports the notification Network_Connection.
USB_CDC_ACM_SUPPORT_NOTIFY_REQUESTS = (1 << 3),
};
enum
{
USB_CDC_CTRL_SIGNAL_DTE_PRESENT = (1 << 0), // DTR
USB_CDC_CTRL_SIGNAL_ACTIVATE_CARRIER = (1 << 1), // RTS
};
enum
{
USB_CDC_SERIAL_STATE_DCD = (1 << 0),
USB_CDC_SERIAL_STATE_DSR = (1 << 1),
USB_CDC_SERIAL_STATE_BREAK = (1 << 2),
USB_CDC_SERIAL_STATE_RING = (1 << 3),
USB_CDC_SERIAL_STATE_FRAMING = (1 << 4),
USB_CDC_SERIAL_STATE_PARITY = (1 << 5),
USB_CDC_SERIAL_STATE_OVERRUN = (1 << 6),
};
#define USB_CDC_BREAK_DURATION_DISABLE 0
#define USB_CDC_BREAK_DURATION_INFINITE 0xffff
/*- Types -------------------------------------------------------------------*/
typedef struct PACK
{
uint8_t bFunctionalLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint16_t bcdCDC;
} usb_cdc_header_functional_descriptor_t;
typedef struct PACK
{
uint8_t bFunctionalLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
} usb_cdc_abstract_control_managment_descriptor_t;
typedef struct PACK
{
uint8_t bFunctionalLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
uint8_t bDataInterface;
} usb_cdc_call_managment_functional_descriptor_t;
typedef struct PACK
{
uint8_t bFunctionalLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bMasterInterface;
uint8_t bSlaveInterface0;
} usb_cdc_union_functional_descriptor_t;
typedef struct PACK
{
uint32_t dwDTERate;
uint8_t bCharFormat;
uint8_t bParityType;
uint8_t bDataBits;
} usb_cdc_line_coding_t;
typedef struct PACK
{
usb_request_t request;
uint16_t value;
} usb_cdc_notify_serial_state_t;
/*- Prototypes --------------------------------------------------------------*/
void usb_cdc_init(void);
bool usb_cdc_handle_request(usb_request_t *request);
void usb_cdc_send(uint8_t *data, int size);
void usb_cdc_recv(uint8_t *data, int size);
void usb_cdc_set_state(int mask);
void usb_cdc_clear_state(int mask);
usb_cdc_line_coding_t *usb_cdc_get_line_coding(void);
void usb_cdc_send_callback(void);
void usb_cdc_recv_callback(int size);
void usb_cdc_line_coding_updated(usb_cdc_line_coding_t *line_coding);
void usb_cdc_control_line_state_update(int line_state);
void usb_cdc_send_break(int duration);
#endif // _USB_CDC_H_

View File

@ -0,0 +1,225 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2017-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdalign.h>
#include "usb.h"
#include "usb_descriptors.h"
/*- Variables ---------------------------------------------------------------*/
const alignas(4) usb_device_descriptor_t usb_device_descriptor =
{
.bLength = sizeof(usb_device_descriptor_t),
.bDescriptorType = USB_DEVICE_DESCRIPTOR,
.bcdUSB = 0x0200,
.bDeviceClass = USB_DEVICE_CLASS_MISCELLANEOUS,
.bDeviceSubClass = USB_DEVICE_SUBCLASS_COMMON,
.bDeviceProtocol = USB_DEVICE_PROTOCOL_INTERFACE_ASSOCIATION,
.bMaxPacketSize0 = USB_CTRL_EP_SIZE,
.idVendor = 0x6666,
.idProduct = 0x6600,
.bcdDevice = 0x0101,
.iManufacturer = USB_STR_MANUFACTURER,
.iProduct = USB_STR_PRODUCT,
.iSerialNumber = USB_STR_SERIAL_NUMBER,
.bNumConfigurations = 1,
};
const alignas(4) usb_configuration_hierarchy_t usb_configuration_hierarchy =
{
.configuration =
{
.bLength = sizeof(usb_configuration_descriptor_t),
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR,
.wTotalLength = sizeof(usb_configuration_hierarchy_t),
.bNumInterfaces = 3,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
.bMaxPower = 250, // 500 mA
},
.hid_interface =
{
.bLength = sizeof(usb_interface_descriptor_t),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_HID_DEVICE_CLASS,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = USB_STR_CMSIS_DAP,
},
.hid =
{
.bLength = sizeof(usb_hid_descriptor_t),
.bDescriptorType = USB_HID_DESCRIPTOR,
.bcdHID = 0x0111,
.bCountryCode = 0,
.bNumDescriptors = 1,
.bDescriptorType1 = USB_HID_REPORT_DESCRIPTOR,
.wDescriptorLength = sizeof(usb_hid_report_descriptor),
},
.hid_ep_in =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_IN_ENDPOINT | USB_HID_EP_SEND,
.bmAttributes = USB_INTERRUPT_ENDPOINT,
.wMaxPacketSize = 64,
.bInterval = 1,
},
.hid_ep_out =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_OUT_ENDPOINT | USB_HID_EP_RECV,
.bmAttributes = USB_INTERRUPT_ENDPOINT,
.wMaxPacketSize = 64,
.bInterval = 1,
},
.iad =
{
.bLength = sizeof(usb_interface_association_descriptor_t),
.bDescriptorType = USB_INTERFACE_ASSOCIATION_DESCRIPTOR,
.bFirstInterface = 1,
.bInterfaceCount = 2,
.bFunctionClass = USB_CDC_COMM_CLASS,
.bFunctionSubClass = USB_CDC_ACM_SUBCLASS,
.bFunctionProtocol = 0,
.iFunction = USB_STR_COM_PORT,
},
.interface_comm =
{
.bLength = sizeof(usb_interface_descriptor_t),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
.bInterfaceNumber = 1,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CDC_COMM_CLASS,
.bInterfaceSubClass = USB_CDC_ACM_SUBCLASS,
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.cdc_header =
{
.bFunctionalLength = sizeof(usb_cdc_header_functional_descriptor_t),
.bDescriptorType = USB_CS_INTERFACE_DESCRIPTOR,
.bDescriptorSubtype = USB_CDC_HEADER_SUBTYPE,
.bcdCDC = 0x0110,
},
.cdc_acm =
{
.bFunctionalLength = sizeof(usb_cdc_abstract_control_managment_descriptor_t),
.bDescriptorType = USB_CS_INTERFACE_DESCRIPTOR,
.bDescriptorSubtype = USB_CDC_ACM_SUBTYPE,
.bmCapabilities = USB_CDC_ACM_SUPPORT_LINE_REQUESTS | USB_CDC_ACM_SUPPORT_SENDBREAK_REQUESTS,
},
.cdc_call_mgmt =
{
.bFunctionalLength = sizeof(usb_cdc_call_managment_functional_descriptor_t),
.bDescriptorType = USB_CS_INTERFACE_DESCRIPTOR,
.bDescriptorSubtype = USB_CDC_CALL_MGMT_SUBTYPE,
.bmCapabilities = USB_CDC_CALL_MGMT_OVER_DCI,
.bDataInterface = 2,
},
.cdc_union =
{
.bFunctionalLength = sizeof(usb_cdc_union_functional_descriptor_t),
.bDescriptorType = USB_CS_INTERFACE_DESCRIPTOR,
.bDescriptorSubtype = USB_CDC_UNION_SUBTYPE,
.bMasterInterface = 1,
.bSlaveInterface0 = 2,
},
.ep_comm =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_IN_ENDPOINT | USB_CDC_EP_COMM,
.bmAttributes = USB_INTERRUPT_ENDPOINT,
.wMaxPacketSize = 64,
.bInterval = 1,
},
.interface_data =
{
.bLength = sizeof(usb_interface_descriptor_t),
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
.bInterfaceNumber = 2,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CDC_DATA_CLASS,
.bInterfaceSubClass = USB_CDC_NO_SUBCLASS,
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.ep_in =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_IN_ENDPOINT | USB_CDC_EP_SEND,
.bmAttributes = USB_BULK_ENDPOINT,
.wMaxPacketSize = 64,
.bInterval = 0,
},
.ep_out =
{
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_OUT_ENDPOINT | USB_CDC_EP_RECV,
.bmAttributes = USB_BULK_ENDPOINT,
.wMaxPacketSize = 64,
.bInterval = 0,
},
};
const alignas(4) uint8_t usb_hid_report_descriptor[28] =
{
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x00, // Usage (Undefined)
0xa1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x40, // Report Count (64)
0x09, 0x00, // Usage (Undefined)
0x81, 0x82, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x40, // Report Count (64)
0x09, 0x00, // Usage (Undefined)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0xc0, // End Collection
};
const alignas(4) usb_string_descriptor_zero_t usb_string_descriptor_zero =
{
.bLength = sizeof(usb_string_descriptor_zero_t),
.bDescriptorType = USB_STRING_DESCRIPTOR,
.wLANGID = 0x0409, // English (United States)
};
char usb_serial_number[16];
const char *usb_strings[] =
{
[USB_STR_MANUFACTURER] = "Alex Taradov",
[USB_STR_PRODUCT] = "Combined VCP and CMSIS-DAP Adapter",
[USB_STR_COM_PORT] = "Virtual COM-Port",
[USB_STR_CMSIS_DAP] = "CMSIS-DAP Adapter",
[USB_STR_SERIAL_NUMBER] = usb_serial_number,
};

View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _USB_DESCRIPTORS_H_
#define _USB_DESCRIPTORS_H_
/*- Includes ----------------------------------------------------------------*/
#include "usb.h"
#include "usb_std.h"
#include "usb_cdc.h"
#include "usb_hid.h"
/*- Definitions -------------------------------------------------------------*/
enum
{
USB_STR_ZERO,
USB_STR_MANUFACTURER,
USB_STR_PRODUCT,
USB_STR_COM_PORT,
USB_STR_CMSIS_DAP,
USB_STR_SERIAL_NUMBER,
USB_STR_COUNT,
};
enum
{
USB_HID_EP_SEND = 1,
USB_HID_EP_RECV = 2,
USB_CDC_EP_COMM = 3,
USB_CDC_EP_SEND = 4,
USB_CDC_EP_RECV = 5,
};
/*- Types -------------------------------------------------------------------*/
typedef struct PACK
{
usb_configuration_descriptor_t configuration;
usb_interface_descriptor_t hid_interface;
usb_hid_descriptor_t hid;
usb_endpoint_descriptor_t hid_ep_in;
usb_endpoint_descriptor_t hid_ep_out;
usb_interface_association_descriptor_t iad;
usb_interface_descriptor_t interface_comm;
usb_cdc_header_functional_descriptor_t cdc_header;
usb_cdc_abstract_control_managment_descriptor_t cdc_acm;
usb_cdc_call_managment_functional_descriptor_t cdc_call_mgmt;
usb_cdc_union_functional_descriptor_t cdc_union;
usb_endpoint_descriptor_t ep_comm;
usb_interface_descriptor_t interface_data;
usb_endpoint_descriptor_t ep_in;
usb_endpoint_descriptor_t ep_out;
} usb_configuration_hierarchy_t;
//-----------------------------------------------------------------------------
extern const usb_device_descriptor_t usb_device_descriptor;
extern const usb_configuration_hierarchy_t usb_configuration_hierarchy;
extern const uint8_t usb_hid_report_descriptor[28];
extern const usb_string_descriptor_zero_t usb_string_descriptor_zero;
extern const char *usb_strings[];
extern char usb_serial_number[16];
#endif // _USB_DESCRIPTORS_H_

72
platform/rp2040/usb_hid.c Normal file
View File

@ -0,0 +1,72 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdbool.h>
#include <stdalign.h>
#include <string.h>
#include "utils.h"
#include "usb.h"
#include "usb_std.h"
#include "usb_hid.h"
#include "usb_descriptors.h"
/*- Prototypes --------------------------------------------------------------*/
static void usb_hid_ep_send_callback(int size);
static void usb_hid_ep_recv_callback(int size);
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
void usb_hid_init(void)
{
usb_set_callback(USB_HID_EP_SEND, usb_hid_ep_send_callback);
usb_set_callback(USB_HID_EP_RECV, usb_hid_ep_recv_callback);
}
//-----------------------------------------------------------------------------
void usb_hid_send(uint8_t *data, int size)
{
usb_send(USB_HID_EP_SEND, data, size);
}
//-----------------------------------------------------------------------------
void usb_hid_recv(uint8_t *data, int size)
{
usb_recv(USB_HID_EP_RECV, data, size);
}
//-----------------------------------------------------------------------------
static void usb_hid_ep_send_callback(int size)
{
usb_hid_send_callback();
(void)size;
}
//-----------------------------------------------------------------------------
static void usb_hid_ep_recv_callback(int size)
{
usb_hid_recv_callback(size);
}
//-----------------------------------------------------------------------------
bool usb_hid_handle_request(usb_request_t *request)
{
int length = request->wLength;
switch ((request->bRequest << 8) | request->bmRequestType)
{
case USB_CMD(IN, INTERFACE, STANDARD, GET_DESCRIPTOR):
{
length = LIMIT(length, sizeof(usb_hid_report_descriptor));
usb_control_send((uint8_t *)usb_hid_report_descriptor, length);
} break;
default:
return false;
}
return true;
}

48
platform/rp2040/usb_hid.h Normal file
View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _USB_HID_H_
#define _USB_HID_H_
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "utils.h"
#include "usb_std.h"
/*- Definitions -------------------------------------------------------------*/
enum
{
USB_HID_DESCRIPTOR = 0x21,
USB_HID_REPORT_DESCRIPTOR = 0x22,
USB_HID_PHYSICAL_DESCRIPTOR = 0x23,
};
enum
{
USB_HID_DEVICE_CLASS = 3, // USB Human Interface Device Class
};
/*- Types -------------------------------------------------------------------*/
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
uint8_t bDescriptorType1;
uint16_t wDescriptorLength;
} usb_hid_descriptor_t;
/*- Prototypes --------------------------------------------------------------*/
void usb_hid_init(void);
bool usb_hid_handle_request(usb_request_t *request);
void usb_hid_send(uint8_t *data, int size);
void usb_hid_recv(uint8_t *data, int size);
void usb_hid_send_callback(void);
void usb_hid_recv_callback(int size);
#endif // _USB_HID_H_

242
platform/rp2040/usb_std.c Normal file
View File

@ -0,0 +1,242 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2016-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdbool.h>
#include <stdalign.h>
#include <string.h>
#include "utils.h"
#include "usb.h"
#include "usb_std.h"
#include "usb_descriptors.h"
/*- Types -------------------------------------------------------------------*/
typedef void (*usb_ep_callback_t)(int size);
/*- Variables ---------------------------------------------------------------*/
static usb_ep_callback_t usb_ep_callbacks[USB_EP_NUM];
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
void usb_init(void)
{
for (int i = 0; i < USB_EP_NUM; i++)
usb_ep_callbacks[i] = NULL;
usb_hw_init();
}
//-----------------------------------------------------------------------------
void usb_set_callback(int ep, void (*callback)(int size))
{
usb_ep_callbacks[ep] = callback;
}
//-----------------------------------------------------------------------------
WEAK bool usb_class_handle_request(usb_request_t *request)
{
(void)request;
return false;
}
//-----------------------------------------------------------------------------
bool usb_handle_standard_request(usb_request_t *request)
{
static int usb_config = 0;
switch ((request->bRequest << 8) | request->bmRequestType)
{
case USB_CMD(IN, DEVICE, STANDARD, GET_DESCRIPTOR):
{
int type = request->wValue >> 8;
int index = request->wValue & 0xff;
int length = request->wLength;
if (USB_DEVICE_DESCRIPTOR == type)
{
length = LIMIT(length, usb_device_descriptor.bLength);
usb_control_send((uint8_t *)&usb_device_descriptor, length);
}
else if (USB_CONFIGURATION_DESCRIPTOR == type)
{
length = LIMIT(length, usb_configuration_hierarchy.configuration.wTotalLength);
usb_control_send((uint8_t *)&usb_configuration_hierarchy, length);
}
else if (USB_STRING_DESCRIPTOR == type)
{
if (0 == index)
{
length = LIMIT(length, usb_string_descriptor_zero.bLength);
usb_control_send((uint8_t *)&usb_string_descriptor_zero, length);
}
else if (index < USB_STR_COUNT)
{
const char *str = usb_strings[index];
int len = strlen(str);
int size = len*2 + 2;
alignas(4) uint8_t buf[size];
buf[0] = size;
buf[1] = USB_STRING_DESCRIPTOR;
for (int i = 0; i < len; i++)
{
buf[2 + i*2] = str[i];
buf[3 + i*2] = 0;
}
length = LIMIT(length, size);
usb_control_send(buf, length);
}
else
{
return false;
}
}
else
{
return false;
}
} break;
case USB_CMD(OUT, DEVICE, STANDARD, SET_ADDRESS):
{
usb_control_send_zlp();
usb_set_address(request->wValue);
} break;
case USB_CMD(OUT, DEVICE, STANDARD, SET_CONFIGURATION):
{
usb_config = request->wValue;
usb_control_send_zlp();
if (usb_config)
{
int size = usb_configuration_hierarchy.configuration.wTotalLength;
usb_descriptor_header_t *desc = (usb_descriptor_header_t *)&usb_configuration_hierarchy;
while (size)
{
if (USB_ENDPOINT_DESCRIPTOR == desc->bDescriptorType)
usb_configure_endpoint((usb_endpoint_descriptor_t *)desc);
size -= desc->bLength;
desc = (usb_descriptor_header_t *)((uint8_t *)desc + desc->bLength);
}
usb_configuration_callback(usb_config);
}
} break;
case USB_CMD(IN, DEVICE, STANDARD, GET_CONFIGURATION):
{
uint8_t config = usb_config;
usb_control_send(&config, sizeof(config));
} break;
case USB_CMD(IN, DEVICE, STANDARD, GET_STATUS):
case USB_CMD(IN, INTERFACE, STANDARD, GET_STATUS):
{
uint16_t status = 0;
usb_control_send((uint8_t *)&status, sizeof(status));
} break;
case USB_CMD(IN, ENDPOINT, STANDARD, GET_STATUS):
{
int ep = request->wIndex & USB_INDEX_MASK;
int dir = request->wIndex & USB_DIRECTION_MASK;
uint16_t status = 0;
if (usb_endpoint_configured(ep, dir))
{
status = usb_endpoint_get_status(ep, dir);
usb_control_send((uint8_t *)&status, sizeof(status));
}
else
{
return false;
}
} break;
case USB_CMD(OUT, DEVICE, STANDARD, SET_FEATURE):
{
return false;
} break;
case USB_CMD(OUT, INTERFACE, STANDARD, SET_FEATURE):
{
usb_control_send_zlp();
} break;
case USB_CMD(OUT, ENDPOINT, STANDARD, SET_FEATURE):
{
int ep = request->wIndex & USB_INDEX_MASK;
int dir = request->wIndex & USB_DIRECTION_MASK;
if (0 == request->wValue && ep && usb_endpoint_configured(ep, dir))
{
usb_endpoint_set_feature(ep, dir);
usb_control_send_zlp();
}
else
{
return false;
}
} break;
case USB_CMD(OUT, DEVICE, STANDARD, CLEAR_FEATURE):
{
return false;
} break;
case USB_CMD(OUT, INTERFACE, STANDARD, CLEAR_FEATURE):
{
usb_control_send_zlp();
} break;
case USB_CMD(OUT, ENDPOINT, STANDARD, CLEAR_FEATURE):
{
int ep = request->wIndex & USB_INDEX_MASK;
int dir = request->wIndex & USB_DIRECTION_MASK;
if (0 == request->wValue && ep && usb_endpoint_configured(ep, dir))
{
usb_endpoint_clear_feature(ep, dir);
usb_control_send_zlp();
}
else
{
return false;
}
} break;
default:
{
if (!usb_class_handle_request(request))
return false;
} break;
}
return true;
}
//-----------------------------------------------------------------------------
void usb_send_callback(int ep)
{
if (usb_ep_callbacks[ep])
usb_ep_callbacks[ep](0);
}
//-----------------------------------------------------------------------------
void usb_recv_callback(int ep, int size)
{
if (usb_ep_callbacks[ep])
usb_ep_callbacks[ep](size);
}

216
platform/rp2040/usb_std.h Normal file
View File

@ -0,0 +1,216 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2016-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _USB_STD_H_
#define _USB_STD_H_
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "utils.h"
/*- Definitions -------------------------------------------------------------*/
enum
{
USB_GET_STATUS = 0,
USB_CLEAR_FEATURE = 1,
USB_SET_FEATURE = 3,
USB_SET_ADDRESS = 5,
USB_GET_DESCRIPTOR = 6,
USB_SET_DESCRIPTOR = 7,
USB_GET_CONFIGURATION = 8,
USB_SET_CONFIGURATION = 9,
USB_GET_INTERFACE = 10,
USB_SET_INTERFACE = 11,
USB_SYNCH_FRAME = 12,
};
enum
{
USB_DEVICE_DESCRIPTOR = 1,
USB_CONFIGURATION_DESCRIPTOR = 2,
USB_STRING_DESCRIPTOR = 3,
USB_INTERFACE_DESCRIPTOR = 4,
USB_ENDPOINT_DESCRIPTOR = 5,
USB_DEVICE_QUALIFIER_DESCRIPTOR = 6,
USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR = 7,
USB_INTERFACE_POWER_DESCRIPTOR = 8,
USB_OTG_DESCRIPTOR = 9,
USB_DEBUG_DESCRIPTOR = 10,
USB_INTERFACE_ASSOCIATION_DESCRIPTOR = 11,
USB_BINARY_OBJECT_STORE_DESCRIPTOR = 15,
USB_DEVICE_CAPABILITY_DESCRIPTOR = 16,
USB_CS_INTERFACE_DESCRIPTOR = 36,
};
enum
{
USB_DEVICE_RECIPIENT = 0,
USB_INTERFACE_RECIPIENT = 1,
USB_ENDPOINT_RECIPIENT = 2,
USB_OTHER_RECIPIENT = 3,
};
enum
{
USB_STANDARD_REQUEST = 0,
USB_CLASS_REQUEST = 1,
USB_VENDOR_REQUEST = 2,
};
enum
{
USB_OUT_TRANSFER = 0,
USB_IN_TRANSFER = 1,
};
enum
{
USB_IN_ENDPOINT = 0x80,
USB_OUT_ENDPOINT = 0x00,
USB_INDEX_MASK = 0x7f,
USB_DIRECTION_MASK = 0x80,
};
enum
{
USB_CONTROL_ENDPOINT = 0 << 0,
USB_ISOCHRONOUS_ENDPOINT = 1 << 0,
USB_BULK_ENDPOINT = 2 << 0,
USB_INTERRUPT_ENDPOINT = 3 << 0,
USB_NO_SYNCHRONIZATION = 0 << 2,
USB_ASYNCHRONOUS = 1 << 2,
USB_ADAPTIVE = 2 << 2,
USB_SYNCHRONOUS = 3 << 2,
USB_DATA_ENDPOINT = 0 << 4,
USB_FEEDBACK_ENDPOINT = 1 << 4,
USB_IMP_FB_DATA_ENDPOINT = 2 << 4,
};
enum
{
USB_DEVICE_CLASS_MISCELLANEOUS = 0xef,
};
enum
{
USB_DEVICE_SUBCLASS_COMMON = 0x02,
};
enum
{
USB_DEVICE_PROTOCOL_INTERFACE_ASSOCIATION = 0x01,
};
#define USB_CTRL_EP_SIZE 64
#define USB_CMD(dir, rcpt, type, cmd) \
((USB_##cmd << 8) | (USB_##dir##_TRANSFER << 7) | \
(USB_##type##_REQUEST << 5) | (USB_##rcpt##_RECIPIENT << 0))
/*- Types -------------------------------------------------------------------*/
typedef struct PACK
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} usb_request_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
} usb_descriptor_header_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} usb_device_descriptor_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} usb_configuration_descriptor_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} usb_interface_descriptor_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} usb_endpoint_descriptor_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wLANGID;
} usb_string_descriptor_zero_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bString;
} usb_string_descriptor_t;
typedef struct PACK
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
} usb_interface_association_descriptor_t;
/*- Prototypes --------------------------------------------------------------*/
void usb_init(void);
void usb_set_callback(int ep, void (*callback)(int size));
bool usb_handle_standard_request(usb_request_t *request);
void usb_send_callback(int ep);
void usb_recv_callback(int ep, int size);
#endif // _USB_STD_H_

14
platform/rp2040/utils.h Normal file
View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2016-2022, Alex Taradov <alex@taradov.com>. All rights reserved.
#ifndef _UTILS_H_
#define _UTILS_H_
/*- Definitions -------------------------------------------------------------*/
#define PACK __attribute__((packed))
#define WEAK __attribute__((weak))
#define INLINE static inline __attribute__((always_inline))
#define LIMIT(a, b) (((int)(a) > (int)(b)) ? (int)(b) : (int)(a))
#endif // _UTILS_H_