diff --git a/README.md b/README.md index dad40ff..f5b9cc3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ # coax -Tools for interfacing with [IBM 3270](https://en.wikipedia.org/wiki/IBM_3270) type terminals. +Tools for connecting to real [IBM 3270](https://en.wikipedia.org/wiki/IBM_3270) type terminals. -## Contents +## Documentation * [protocol](protocol/protocol.md) - Protocol documentation -* [interface1](interface1) - A serial attached Arduino interface using the National Semiconductor DP8340 and DP8341 + +## Hardware + +* [interface1](interface1) - Legacy interface using obsolete National Semiconductor DP8340 and DP8341 +* [interface2](interface2) - Modern interface using a Lattice iCE40 FPGA and STM32 microcontroller + +## Software + * [pycoax](pycoax) - Python interface library ## See Also diff --git a/interface1/.images/hero.jpg b/interface1/.images/hero.jpg new file mode 100644 index 0000000..20cd8b3 Binary files /dev/null and b/interface1/.images/hero.jpg differ diff --git a/interface1/README.md b/interface1/README.md index 95ca69a..4f7cde7 100644 --- a/interface1/README.md +++ b/interface1/README.md @@ -1,30 +1,18 @@ # interface1 -A serial attached Arduino interface using the National Semiconductor DP8340 and DP8341. +Legacy interface using obsolete National Semiconductor DP8340 and DP8341. + +![interface1 assembled](.images/hero.jpg) + +This project uses several obsolete components; you may be able to find these as _new old stock_. See [interface2](../interface2) for a modern alternative using a Lattice iCE40 FPGA and STM32 microcontroller. ## Hardware -You can find the Gerber files for fabricating a PCB in the [fabrication](hardware/fabrication) directory. I have used JLCPCB to make the PCBs. - This interface requires an [Arduino Mega 2560 R3](https://store.arduino.cc/usa/mega-2560-r3). - Item | Quantity | Description | Reference | Part Number | Source -:----:|---------:|-------------------------------|------------|-------------------------------|---------------- -1 | 1 | IBM 3270 Protocol Transmitter | U1 | National Semiconductor DP8340 | Obsolete - eBay -2 | 1 | IBM 3270 Protocol Receiver | U2 | National Semiconductor DP8341 | Obsolete - eBay -3 | 1 | Quad RS-422 Line Driver | U3 | Texas Instruments DS3487 | Obsolete - eBay -4 | 1 | Pulse Transformer - 1:1:1 | T1 | Pulse PE-5762 | Obsolete - eBay -5 | 1 | Crystal - 18.867 MHz | Y1 | IQD LFXTAL057125 * | [Mouser](https://www.mouser.com/ProductDetail/IQD/LFXTAL057125Bulk?qs=%2Fha2pyFaduieSzBxw7UAJRZlCXjBZuIKPyofrMyYW7wVunrhuBMeiQd4MCF50LLz) -6 | 2 | Resistor - 33 ohm | R2, R4 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-33-RC?qs=sGAEpiMZZMu61qfTUdNhGzoeXLT9qgk%252BV159XfY8c4Q%3D) -7 | 1 | Resistor - 120 ohm | R6 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-120-RC?qs=sGAEpiMZZMu61qfTUdNhG7Of23Pr6gu8rRE5UXBJoDw%3D) -8 | 2 | Resistor - 150 ohm | R1, R5 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-150-RC?qs=sGAEpiMZZMu61qfTUdNhG2ZzrN2CiS9nBcPQNrtAXYk%3D) -9 | 1 | Resistor - 500 ohm | R7 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-499-RC?qs=sGAEpiMZZMu61qfTUdNhG6lpw21m8SOsvE2iEnaSg1s%3D) -10 | 1 | Resistor - 510 ohm | R3 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-510-RC?qs=sGAEpiMZZMu61qfTUdNhG9RrhBeDi8B8FBVTnOgGHiw%3D) -11 | 1 | Capacitor - 30 pF | C1 | | [Mouser](https://www.mouser.com/ProductDetail/Vishay-Cera-Mite/561R10TCCQ30?qs=sGAEpiMZZMt1mVBmZSXTPNbSVgF1iSv4q4pBhPBLwuM%3D) -12 | 3 | Capacitor - 0.1 uF | C2, C3, C4 | | [Mouser](https://www.mouser.com/ProductDetail/Vishay-BC-Components/K104K15X7RF53L2?qs=%2Fha2pyFadujZBSsyKhN2cCnGMY0oYMxsnapy5diPgBuVoINU4ePXMg%3D%3D) -13 | 1 | BNC Jack | J1 | | [Mouser](https://www.mouser.com/ProductDetail/TE-Connectivity/5227161-3?qs=%2Fha2pyFaduiGA%252Bh8aDcjGvgxten7RGi%2FL59ZMwKXDjte07aSAL7vPw%3D%3D) +You can find a [complete BOM](https://octopart.com/bom-tool/SZ3rSPgD) on Octopart. I have purchased all current components from Mouser and obsolete ones from eBay. -\* - SMD +You can find the Gerber files for fabricating a PCB in the [fabrication](hardware/fabrication) directory. I have used JLCPCB to make the PCBs. ## Firmware diff --git a/interface2/.images/hero.jpg b/interface2/.images/hero.jpg new file mode 100644 index 0000000..0827a71 Binary files /dev/null and b/interface2/.images/hero.jpg differ diff --git a/interface2/README.md b/interface2/README.md new file mode 100644 index 0000000..0e50412 --- /dev/null +++ b/interface2/README.md @@ -0,0 +1,37 @@ +# interface2 + +Modern interface using a Lattice iCE40 FPGA and STM32 microcontroller. + +![interface2 assembled](.images/hero.jpg) + +## Hardware + +You can find a [complete BOM](https://octopart.com/bom-tool/S80JaI18) on Octopart. + +You can find the Gerber files for fabricating a PCB in the [fabrication](pcb/fabrication) directory. I have used JLCPCB to make the PCBs. + +## FPGA + +For now, the FPGA bitstream must be built using Lattice iCEcube2. + +``` +cd fpga +make +``` + +Uses FIFO module from [Sylvain Munaut](https://github.com/smunaut). + +## Firmware + +The firmware currently provides the ability to send commands and receive responses - it is designed to implement a terminal controller, not a terminal. + +You will need [PlatformIO](https://platformio.org/) to build and upload the firmware, only Platform IO Core (the CLI) is required. + +Before building the firmware, you will need to generate the FPGA bitstream; see the steps above. + +To build and upload the firmware using USB DFU: + +``` +cd firmware +platformio run -t upload +``` diff --git a/interface2/firmware/.gitignore b/interface2/firmware/.gitignore new file mode 100644 index 0000000..6ded746 --- /dev/null +++ b/interface2/firmware/.gitignore @@ -0,0 +1,2 @@ +.pio +src/bitstream.inc diff --git a/interface2/firmware/boards/stm32l443cc.json b/interface2/firmware/boards/stm32l443cc.json new file mode 100644 index 0000000..9c075f2 --- /dev/null +++ b/interface2/firmware/boards/stm32l443cc.json @@ -0,0 +1,38 @@ +{ + "build": { + "cpu": "cortex-m4", + "extra_flags": "-DSTM32L443xx", + "f_cpu": "80000000L", + "mcu": "stm32l443ccu6", + "product_line": "stm32l443xx", + "variant": "STM32L443CC" + }, + "connectivity": [ + ], + "debug": { + "default_tools": [ + "stlink" + ], + "jlink_device": "STM32L443CC", + "onboard_tools": [ + "stlink" + ], + "openocd_board": "xxx", + "svd_path": "STM32L4x3.svd" + }, + "frameworks": [ + "stm32cube" + ], + "name": "STM32L443CC", + "upload": { + "maximum_ram_size": 65536, + "maximum_size": 262144, + "protocol": "stlink", + "protocols": [ + "dfu", + "stlink" + ] + }, + "url": "https://www.st.com/en/microcontrollers-microprocessors/stm32l443cc.html", + "vendor": "ST" +} diff --git a/interface2/firmware/generate_bitstream_inc.sh b/interface2/firmware/generate_bitstream_inc.sh new file mode 100755 index 0000000..8eacafe --- /dev/null +++ b/interface2/firmware/generate_bitstream_inc.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +BITSTREAM=../fpga/rtl/top.bin + +if [ ! -f $BITSTREAM ]; then + echo "Bitstream '$BITSTREAM' not found." >&2 + exit 1 +fi + +if [ ! $BITSTREAM -nt "src/bitstream.inc" ]; then + echo "Bitstream '$BITSTREAM' is not newer than generated include file, skipping." >&2 + exit +fi + +xxd -i $BITSTREAM | tail -n +2 | head -n -2 > src/bitstream.inc diff --git a/interface2/firmware/include/coax.h b/interface2/firmware/include/coax.h new file mode 100644 index 0000000..85d53e2 --- /dev/null +++ b/interface2/firmware/include/coax.h @@ -0,0 +1,118 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include +#include + +#define COAX_ERROR_TX_RECEIVER_ACTIVE -1 +#define COAX_ERROR_TX_UNDERFLOW -2 + +#define COAX_ERROR_RX_LOSS_OF_MID_BIT_TRANSITION -1 +#define COAX_ERROR_RX_PARITY -2 +#define COAX_ERROR_RX_INVALID_END_SEQUENCE -4 +#define COAX_ERROR_RX_OVERFLOW -8 +#define COAX_ERROR_RX_UNKNOWN -513 + +#define COAX_ERROR_NOT_INITIALIZED -1024 + +enum class CoaxParity +{ + Odd = 0, + Even = 1 +}; + +class SPICoaxTransceiver; + +class Coax +{ +public: + Coax(SPICoaxTransceiver &spiCoaxTransceiver, CoaxParity parity, + volatile uint16_t *buffer, size_t bufferSize); + + bool init(); + + void reset(); + + int transmit(const uint16_t *buffer, size_t bufferCount); + int receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout); + + void handleInterrupt(); + +private: + SPICoaxTransceiver &_spiCoaxTransceiver; + CoaxParity _parity; + + bool _isInitialized; + + volatile enum { + COAX_INTERRUPT_STATE_IDLE, + COAX_INTERRUPT_STATE_DISABLED, + COAX_INTERRUPT_STATE_RECEIVING, + COAX_INTERRUPT_STATE_RECEIVED, + COAX_INTERRUPT_STATE_ERROR + } _interruptState = COAX_INTERRUPT_STATE_DISABLED; + + volatile uint16_t *_buffer; + size_t _bufferSize; + volatile size_t _bufferCount = 0; + volatile int _error = 0; +}; + +#define COAX_REGISTER_STATUS 0x1 +#define COAX_REGISTER_STATUS_RX_ERROR 0x40 +#define COAX_REGISTER_STATUS_RX_ACTIVE 0x20 +#define COAX_REGISTER_STATUS_TX_COMPLETE 0x08 +#define COAX_REGISTER_STATUS_TX_ACTIVE 0x04 + +#define COAX_REGISTER_CONTROL 0x2 +#define COAX_REGISTER_CONTROL_LOOPBACK 0x01 +#define COAX_REGISTER_CONTROL_TX_PARITY 0x08 +#define COAX_REGISTER_CONTROL_RX_PARITY 0x40 + +#define COAX_REGISTER_DEVICE_ID 0xf + +class SPICoaxTransceiver +{ +public: + SPICoaxTransceiver(); + + bool init(); + + void reset(); + + uint8_t readRegister(uint8_t index); + void writeRegister(uint8_t index, uint8_t value, uint8_t mask); + + int transmit(const uint16_t *buffer, size_t bufferCount); + int receive(uint16_t *buffer, size_t bufferSize); + + void setLoopback(bool loopback); + void setTXParity(CoaxParity parity); + void setRXParity(CoaxParity parity); + + inline bool isTXComplete() + { + return readRegister(COAX_REGISTER_STATUS) & COAX_REGISTER_STATUS_TX_COMPLETE; + } + + inline bool isRXActive() + { + return readRegister(COAX_REGISTER_STATUS) & COAX_REGISTER_STATUS_RX_ACTIVE; + }; + +private: + void spiTransfer(const uint8_t *transmitBuffer, uint8_t *receiveBuffer, size_t count); +}; diff --git a/interface2/firmware/include/config.h b/interface2/firmware/include/config.h new file mode 100644 index 0000000..dbfec0e --- /dev/null +++ b/interface2/firmware/include/config.h @@ -0,0 +1,26 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +// The coax buffer size is based on the maximum receive size, which as a +// controller should be limited. +#define COAX_BUFFER_SIZE 32 + +// The message buffer size is based on the maximum conceivable coax write +// data command length which in turn assumes a maximum regen and EAB buffer +// being written in a single command. +#define MAX_COAX_WRITE_SIZE (1 + (3696 * 2)) + +#define MESSAGE_BUFFER_SIZE ((MAX_COAX_WRITE_SIZE * sizeof(uint16_t)) + 32) diff --git a/interface2/firmware/include/cubemx/main.h b/interface2/firmware/include/cubemx/main.h new file mode 100644 index 0000000..23fb270 --- /dev/null +++ b/interface2/firmware/include/cubemx/main.h @@ -0,0 +1,82 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx_hal.h" +#include "stm32l4xx_ll_crs.h" +#include "stm32l4xx_ll_rcc.h" +#include "stm32l4xx_ll_bus.h" +#include "stm32l4xx_ll_system.h" +#include "stm32l4xx_ll_exti.h" +#include "stm32l4xx_ll_cortex.h" +#include "stm32l4xx_ll_utils.h" +#include "stm32l4xx_ll_pwr.h" +#include "stm32l4xx_ll_dma.h" +#include "stm32l4xx_ll_spi.h" +#include "stm32l4xx_ll_gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/stm32_assert.h b/interface2/firmware/include/cubemx/stm32_assert.h new file mode 100644 index 0000000..03511c4 --- /dev/null +++ b/interface2/firmware/include/cubemx/stm32_assert.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @file stm32_assert.h + * @brief STM32 assert file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ASSERT_H +#define __STM32_ASSERT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Includes ------------------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ASSERT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/stm32l4xx_hal_conf.h b/interface2/firmware/include/cubemx/stm32l4xx_hal_conf.h new file mode 100644 index 0000000..5945f0c --- /dev/null +++ b/interface2/firmware/include/cubemx/stm32l4xx_hal_conf.h @@ -0,0 +1,483 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32L4xx_HAL_CONF_H +#define STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +/*#define HAL_ADC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_CAN_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +/*#define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_DMA2D_MODULE_ENABLED */ +/*#define HAL_DFSDM_MODULE_ENABLED */ +/*#define HAL_DSI_MODULE_ENABLED */ +/*#define HAL_FIREWALL_MODULE_ENABLED */ +/*#define HAL_GFXMMU_MODULE_ENABLED */ +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LTDC_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_MMC_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +/*#define HAL_PKA_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +/*#define HAL_RTC_MODULE_ENABLED */ +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +/*#define HAL_EXTI_MODULE_ENABLED */ +/*#define HAL_PSSI_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000U) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE 32000U /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE 2097000U /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE 48000U /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 0U /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 0U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Register callback feature configuration ############### */ +/** + * @brief Set below the peripheral configuration to "1U" to add the support + * of HAL callback registration/deregistration feature for the HAL + * driver(s). This allows user application to provide specific callback + * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting + * the default weak callback functions (see each stm32l4xx_hal_ppp.h file + * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef + * for each PPP peripheral). + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U +#define USE_HAL_CAN_REGISTER_CALLBACKS 0U +#define USE_HAL_COMP_REGISTER_CALLBACKS 0U +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U +#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U +#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U +#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U +#define USE_HAL_DSI_REGISTER_CALLBACKS 0U +#define USE_HAL_GFXMMU_REGISTER_CALLBACKS 0U +#define USE_HAL_HASH_REGISTER_CALLBACKS 0U +#define USE_HAL_HCD_REGISTER_CALLBACKS 0U +#define USE_HAL_I2C_REGISTER_CALLBACKS 0U +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U +#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U +#define USE_HAL_MMC_REGISTER_CALLBACKS 0U +#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U +#define USE_HAL_OSPI_REGISTER_CALLBACKS 0U +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U +#define USE_HAL_RNG_REGISTER_CALLBACKS 0U +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U +#define USE_HAL_SAI_REGISTER_CALLBACKS 0U +#define USE_HAL_SD_REGISTER_CALLBACKS 0U +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U +#define USE_HAL_SWPMI_REGISTER_CALLBACKS 0U +#define USE_HAL_TIM_REGISTER_CALLBACKS 0U +#define USE_HAL_TSC_REGISTER_CALLBACKS 0U +#define USE_HAL_UART_REGISTER_CALLBACKS 0U +#define USE_HAL_USART_REGISTER_CALLBACKS 0U +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CAN_LEGACY_MODULE_ENABLED + #include "Legacy/stm32l4xx_hal_can_legacy.h" +#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32l4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32l4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32l4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32l4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED + #include "stm32l4xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32l4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32l4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32l4xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED + #include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED + #include "stm32l4xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED + #include "stm32l4xx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_PSSI_MODULE_ENABLED + #include "stm32l4xx_hal_pssi.h" +#endif /* HAL_PSSI_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t *file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32L4xx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/stm32l4xx_it.h b/interface2/firmware/include/cubemx/stm32l4xx_it.h new file mode 100644 index 0000000..e6616f0 --- /dev/null +++ b/interface2/firmware/include/cubemx/stm32l4xx_it.h @@ -0,0 +1,72 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32l4xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_IT_H +#define __STM32L4xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +void EXTI0_IRQHandler(void); +void TIM6_DAC_IRQHandler(void); +void USB_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/tim.h b/interface2/firmware/include/cubemx/tim.h new file mode 100644 index 0000000..263d87d --- /dev/null +++ b/interface2/firmware/include/cubemx/tim.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * File Name : TIM.h + * Description : This file provides code for the configuration + * of the TIM instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __tim_H +#define __tim_H +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern TIM_HandleTypeDef htim6; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_TIM6_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ tim_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/usb_device.h b/interface2/firmware/include/cubemx/usb_device.h new file mode 100644 index 0000000..7b67ca2 --- /dev/null +++ b/interface2/firmware/include/cubemx/usb_device.h @@ -0,0 +1,105 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usb_device.h + * @version : v2.0_Cube + * @brief : Header for usb_device.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DEVICE__H__ +#define __USB_DEVICE__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx.h" +#include "stm32l4xx_hal.h" +#include "usbd_def.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup USBD_OTG_DRIVER + * @{ + */ + +/** @defgroup USBD_DEVICE USBD_DEVICE + * @brief Device file for Usb otg low level driver. + * @{ + */ + +/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables + * @brief Public variables. + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* + * -- Insert your variables declaration here -- + */ +/* USER CODE BEGIN VARIABLES */ + +/* USER CODE END VARIABLES */ +/** + * @} + */ + +/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype + * @brief Declaration of public functions for Usb device. + * @{ + */ + +/** USB Device initialization function. */ +void MX_USB_DEVICE_Init(void); + +/* + * -- Insert functions declaration here -- + */ +/* USER CODE BEGIN FD */ + +/* USER CODE END FD */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_DEVICE__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/usbd_cdc_if.h b/interface2/firmware/include/cubemx/usbd_cdc_if.h new file mode 100644 index 0000000..cf86596 --- /dev/null +++ b/interface2/firmware/include/cubemx/usbd_cdc_if.h @@ -0,0 +1,134 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_cdc_if.h + * @version : v2.0_Cube + * @brief : Header for usbd_cdc_if.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CDC_IF_H__ +#define __USBD_CDC_IF_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @brief For Usb device. + * @{ + */ + +/** @defgroup USBD_CDC_IF USBD_CDC_IF + * @brief Usb VCP device module + * @{ + */ + +/** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines + * @brief Defines. + * @{ + */ +/* USER CODE BEGIN EXPORTED_DEFINES */ +/* Define size for the receive and transmit buffer over CDC */ +/* It's up to user to redefine and/or remove those define */ +#define APP_RX_DATA_SIZE 1000 +#define APP_TX_DATA_SIZE 1000 + +/* USER CODE END EXPORTED_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Types USBD_CDC_IF_Exported_Types + * @brief Types. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_TYPES */ + +/* USER CODE END EXPORTED_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Macros USBD_CDC_IF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_MACRO */ + +/* USER CODE END EXPORTED_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** CDC Interface callback. */ +extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype + * @brief Public functions declaration. + * @{ + */ + +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); + +/* USER CODE BEGIN EXPORTED_FUNCTIONS */ + +/* USER CODE END EXPORTED_FUNCTIONS */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_CDC_IF_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/usbd_conf.h b/interface2/firmware/include/cubemx/usbd_conf.h new file mode 100644 index 0000000..ffd6a4d --- /dev/null +++ b/interface2/firmware/include/cubemx/usbd_conf.h @@ -0,0 +1,173 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_conf.h + * @version : v2.0_Cube + * @brief : Header for usbd_conf.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CONF__H__ +#define __USBD_CONF__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include +#include "main.h" +#include "stm32l4xx.h" +#include "stm32l4xx_hal.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup USBD_OTG_DRIVER + * @brief Driver for Usb device. + * @{ + */ + +/** @defgroup USBD_CONF USBD_CONF + * @brief Configuration file for Usb otg low level driver. + * @{ + */ + +/** @defgroup USBD_CONF_Exported_Variables USBD_CONF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines + * @brief Defines for configuration of the Usb device. + * @{ + */ + +/*---------- -----------*/ +#define USBD_MAX_NUM_INTERFACES 1U +/*---------- -----------*/ +#define USBD_MAX_NUM_CONFIGURATION 1U +/*---------- -----------*/ +#define USBD_MAX_STR_DESC_SIZ 512U +/*---------- -----------*/ +#define USBD_DEBUG_LEVEL 0U +/*---------- -----------*/ +#define USBD_LPM_ENABLED 1U +/*---------- -----------*/ +#define USBD_SELF_POWERED 1U + +/****************************************/ +/* #define for FS and HS identification */ +#define DEVICE_FS 0 + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* Memory management macros */ + +/** Alias for memory allocation. */ +#define USBD_malloc malloc + +/** Alias for memory release. */ +#define USBD_free free + +/** Alias for memory set. */ +#define USBD_memset memset + +/** Alias for memory copy. */ +#define USBD_memcpy memcpy + +/** Alias for delay. */ +#define USBD_Delay HAL_Delay + +/* DEBUG macros */ + +#if (USBD_DEBUG_LEVEL > 0) +#define USBD_UsrLog(...) printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_UsrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 1) + +#define USBD_ErrLog(...) printf("ERROR: ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_ErrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 2) +#define USBD_DbgLog(...) printf("DEBUG : ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_DbgLog(...) +#endif + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Types USBD_CONF_Exported_Types + * @brief Types. + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_FunctionsPrototype USBD_CONF_Exported_FunctionsPrototype + * @brief Declaration of public functions for Usb device. + * @{ + */ + +/* Exported functions -------------------------------------------------------*/ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_CONF__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/cubemx/usbd_desc.h b/interface2/firmware/include/cubemx/usbd_desc.h new file mode 100644 index 0000000..4bc2299 --- /dev/null +++ b/interface2/firmware/include/cubemx/usbd_desc.h @@ -0,0 +1,145 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_desc.c + * @version : v2.0_Cube + * @brief : Header for usbd_conf.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_DESC__C__ +#define __USBD_DESC__C__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_DESC USBD_DESC + * @brief Usb device descriptors module. + * @{ + */ + +/** @defgroup USBD_DESC_Exported_Constants USBD_DESC_Exported_Constants + * @brief Constants. + * @{ + */ +#define DEVICE_ID1 (UID_BASE) +#define DEVICE_ID2 (UID_BASE + 0x4) +#define DEVICE_ID3 (UID_BASE + 0x8) + +#define USB_SIZ_STRING_SERIAL 0x1A + +/* USER CODE BEGIN EXPORTED_CONSTANTS */ + +/* USER CODE END EXPORTED_CONSTANTS */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines + * @brief Defines. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_DEFINES */ + +/* USER CODE END EXPORTED_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions + * @brief Types. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_TYPES */ + +/* USER CODE END EXPORTED_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_MACRO */ + +/* USER CODE END EXPORTED_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** Descriptor for the Usb device. */ +extern USBD_DescriptorsTypeDef FS_Desc; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype + * @brief Public functions declaration. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_FUNCTIONS */ + +/* USER CODE END EXPORTED_FUNCTIONS */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_DESC__C__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/include/debug.h b/interface2/firmware/include/debug.h new file mode 100644 index 0000000..60695f8 --- /dev/null +++ b/interface2/firmware/include/debug.h @@ -0,0 +1,29 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +class Debug +{ +public: + static bool init(); + + static void banner(); + + static void setMarker(int marker); + static void resetMarker(int marker); + + static void trap(int number); + static void trap(int number, const char *format, ...); +}; diff --git a/interface2/firmware/include/ice40.h b/interface2/firmware/include/ice40.h new file mode 100644 index 0000000..7a82109 --- /dev/null +++ b/interface2/firmware/include/ice40.h @@ -0,0 +1,34 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include +#include + +class ICE40 +{ +public: + ICE40(); + + bool configure(const uint8_t *bitstream, size_t bitstreamCount); + + inline bool isConfigured() + { + return _isConfigured; + } + +private: + bool _isConfigured; +}; diff --git a/interface2/firmware/include/indicators.h b/interface2/firmware/include/indicators.h new file mode 100644 index 0000000..5bd6423 --- /dev/null +++ b/interface2/firmware/include/indicators.h @@ -0,0 +1,43 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +enum IndicatorsStatus { + INDICATORS_STATUS_UNKNOWN, + INDICATORS_STATUS_CONFIGURING, + INDICATORS_STATUS_RUNNING +}; + +class Indicators +{ +public: + Indicators(); + + void init(); + + void setStatus(IndicatorsStatus status); + + void tx(); + void rx(); + void error(); + + void update(); + +private: + volatile IndicatorsStatus _status; + volatile uint8_t _txState; + volatile uint8_t _rxState; + volatile uint8_t _errorState; +}; diff --git a/interface2/firmware/include/interface.h b/interface2/firmware/include/interface.h new file mode 100644 index 0000000..a7b4300 --- /dev/null +++ b/interface2/firmware/include/interface.h @@ -0,0 +1,60 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include +#include + +#include "coax.h" +#include "indicators.h" + +#define COMMAND_RESET 0x01 +#define COMMAND_TRANSMIT_RECEIVE 0x06 +#define COMMAND_INFO 0xf0 +#define COMMAND_TEST 0xf1 +#define COMMAND_DFU 0xf2 + +#define INFO_SUPPORTED_QUERIES 0x01 +#define INFO_HARDWARE_TYPE 0x02 +#define INFO_HARDWARE_REVISION 0x03 +#define INFO_HARDWARE_SERIAL 0x04 +#define INFO_FIRMWARE_VERSION 0x05 +#define INFO_MESSAGE_BUFFER_SIZE 0x06 +#define INFO_FEATURES 0x07 + +#define TEST_SUPPORTED_TESTS 0x01 + +#define ERROR_INVALID_MESSAGE 1 +#define ERROR_UNKNOWN_COMMAND 2 +#define ERROR_MESSAGE_TIMEOUT 3 + +class Interface +{ +public: + Interface(Coax &coax, Indicators &indicators); + + void handleMessage(uint8_t *buffer, size_t bufferCount); + void handleError(MessageReceiverError error); + +private: + Coax &_coax; + Indicators &_indicators; + + void handleReset(uint8_t *buffer, size_t bufferCount); + void handleTransmitReceive(uint8_t *buffer, size_t bufferCount); + void handleInfo(uint8_t *buffer, size_t bufferCount); + void handleTest(uint8_t *buffer, size_t bufferCount); + void handleDFU(uint8_t *buffer, size_t bufferCount); +}; diff --git a/interface2/firmware/include/message.h b/interface2/firmware/include/message.h new file mode 100644 index 0000000..2105bc0 --- /dev/null +++ b/interface2/firmware/include/message.h @@ -0,0 +1,60 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include +#include + +enum MessageReceiverError { + MESSAGE_RECEIVER_ERROR_DATA_OVERFLOW, + MESSAGE_RECEIVER_ERROR_MESSAGE_OVERFLOW, + MESSAGE_RECEIVER_ERROR_TIMEOUT +}; + +enum MessageReceiverState { + MESSAGE_RECEIVER_STATE_WAIT_START, + MESSAGE_RECEIVER_STATE_DATA, + MESSAGE_RECEIVER_STATE_ESCAPE, + MESSAGE_RECEIVER_STATE_AVAILABLE, + MESSAGE_RECEIVER_STATE_DATA_OVERFLOW, + MESSAGE_RECEIVER_STATE_MESSAGE_OVERFLOW +}; + +class MessageReceiver +{ +public: + MessageReceiver(volatile uint8_t *buffer, size_t bufferSize, + void (*messageCallback)(const uint8_t *, size_t), + void (*errorCallback)(MessageReceiverError)); + + void load(const uint8_t *buffer, size_t bufferCount); + bool dispatch(); + +private: + uint32_t _timeout; + volatile uint32_t _lastReceiveTime; + volatile uint8_t *_buffer; + size_t _bufferSize; + volatile size_t _bufferCount; + volatile MessageReceiverState _state; + void (*_messageCallback)(const uint8_t *, size_t); + void (*_errorCallback)(MessageReceiverError); +}; + +class MessageSender +{ +public: + static bool send(const uint8_t *buffer, size_t bufferCount); +}; diff --git a/interface2/firmware/include/pins.h b/interface2/firmware/include/pins.h new file mode 100644 index 0000000..6fc7a88 --- /dev/null +++ b/interface2/firmware/include/pins.h @@ -0,0 +1,55 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include "stm32l4xx_ll_gpio.h" + +#define COAX_RESET_Pin GPIO_PIN_3 +#define COAX_RESET_GPIO_Port GPIOA +#define COAX_IRQ_Pin GPIO_PIN_0 +#define COAX_IRQ_GPIO_Port GPIOB +#define COAX_IRQ_EXTI_IRQn EXTI0_IRQn + +#define ICE40_CS_Pin GPIO_PIN_4 +#define ICE40_CS_GPIO_Port GPIOA +#define ICE40_SCK_Pin GPIO_PIN_5 +#define ICE40_SCK_GPIO_Port GPIOA +#define ICE40_SDO_Pin GPIO_PIN_6 +#define ICE40_SDO_GPIO_Port GPIOA +#define ICE40_SDI_Pin GPIO_PIN_7 +#define ICE40_SDI_GPIO_Port GPIOA +#define ICE40_CRESET_Pin GPIO_PIN_1 +#define ICE40_CRESET_GPIO_Port GPIOB +#define ICE40_CDONE_Pin GPIO_PIN_2 +#define ICE40_CDONE_GPIO_Port GPIOB + +#define GPIO0_Pin GPIO_PIN_10 +#define GPIO0_GPIO_Port GPIOB +#define GPIO1_Pin GPIO_PIN_11 +#define GPIO1_GPIO_Port GPIOB + +#define LED_STATUS_Pin GPIO_PIN_12 +#define LED_STATUS_GPIO_Port GPIOB +#define LED_TX_Pin GPIO_PIN_13 +#define LED_TX_GPIO_Port GPIOB +#define LED_RX_Pin GPIO_PIN_14 +#define LED_RX_GPIO_Port GPIOB +#define LED_ERROR_Pin GPIO_PIN_15 +#define LED_ERROR_GPIO_Port GPIOB + +#define USB_D__Pin GPIO_PIN_11 +#define USB_D__GPIO_Port GPIOA +#define USB_D_A12_Pin GPIO_PIN_12 +#define USB_D_A12_GPIO_Port GPIOA diff --git a/interface2/firmware/include/version.h b/interface2/firmware/include/version.h new file mode 100644 index 0000000..2a24736 --- /dev/null +++ b/interface2/firmware/include/version.h @@ -0,0 +1,19 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0 +#define VERSION_PATCH 1 diff --git a/interface2/firmware/platformio.ini b/interface2/firmware/platformio.ini new file mode 100644 index 0000000..4fccb12 --- /dev/null +++ b/interface2/firmware/platformio.ini @@ -0,0 +1,13 @@ +[env:default] +platform = ststm32 +framework = stm32cube +board = stm32l443cc +upload_protocol = dfu +build_flags = + !./generate_bitstream_inc.sh + -Iinclude/cubemx + -DUSE_FULL_LL_DRIVER +src_build_flags = + !echo "-DFIRMWARE_BUILD_WHAT='\""$(git describe --match ForceNone --abbrev=7 --always --dirty=+)"\"'" + !echo "-DFIRMWARE_BUILD_WHO='\""$(whoami)"\"'" + !echo "-DFIRMWARE_BUILD_WHEN='\""$(date)"\"'" diff --git a/interface2/firmware/src/coax.cpp b/interface2/firmware/src/coax.cpp new file mode 100644 index 0000000..cb8f76a --- /dev/null +++ b/interface2/firmware/src/coax.cpp @@ -0,0 +1,469 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include + +#include "stm32l4xx_ll_spi.h" + +#include "pins.h" +#include "debug.h" + +#include "coax.h" + +Coax::Coax(SPICoaxTransceiver &spiCoaxTransceiver, CoaxParity parity, + volatile uint16_t *buffer, size_t bufferSize) : + _spiCoaxTransceiver(spiCoaxTransceiver), + _parity(parity), + _buffer(buffer), + _bufferSize(bufferSize) +{ + _isInitialized = false; +} + +bool Coax::init() +{ + _isInitialized = false; + + _interruptState = COAX_INTERRUPT_STATE_DISABLED; + + if (!_spiCoaxTransceiver.init()) { + return false; + } + + _spiCoaxTransceiver.setTXParity(_parity); + _spiCoaxTransceiver.setRXParity(_parity); + + _isInitialized = true; + + return _isInitialized; +} + +void Coax::reset() +{ + if (!_isInitialized) { + return; + } + + _interruptState = COAX_INTERRUPT_STATE_DISABLED; + + _spiCoaxTransceiver.reset(); + + _spiCoaxTransceiver.setTXParity(_parity); + _spiCoaxTransceiver.setRXParity(_parity); +} + +int Coax::transmit(const uint16_t *buffer, size_t bufferCount) +{ + if (!_isInitialized) { + return COAX_ERROR_NOT_INITIALIZED; + } + + uint8_t status = _spiCoaxTransceiver.readRegister(COAX_REGISTER_STATUS); + + if (status & COAX_REGISTER_STATUS_RX_ACTIVE) { + return COAX_ERROR_TX_RECEIVER_ACTIVE; + } + + if (status & COAX_REGISTER_STATUS_RX_ERROR) { + Debug::trap(101); + + _spiCoaxTransceiver.reset(); + } + + _interruptState = COAX_INTERRUPT_STATE_IDLE; + + return _spiCoaxTransceiver.transmit(buffer, bufferCount); +} + +int Coax::receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout) +{ + if (!_isInitialized) { + return COAX_ERROR_NOT_INITIALIZED; + } + + if (timeout > 0) { + uint32_t startTime = HAL_GetTick(); + + while (_interruptState == COAX_INTERRUPT_STATE_IDLE) { + // https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html#unsigned + if ((HAL_GetTick() - startTime) > timeout) { + return 0; + } + } + } + +uint32_t startTime = HAL_GetTick(); + + while (!(_interruptState == COAX_INTERRUPT_STATE_RECEIVED || _interruptState == COAX_INTERRUPT_STATE_ERROR)) { +if ((HAL_GetTick() - startTime) > 1000) { + Debug::trap(102); +} + } + + int count = 0; + + if (_interruptState == COAX_INTERRUPT_STATE_RECEIVED) { + count = _bufferCount > bufferSize ? bufferSize : _bufferCount; + + memcpy(buffer, const_cast(_buffer), count * sizeof(uint16_t)); + + // TODO: we should be able to manipulate _buffer and not change the state + // to allow multiple calls to this method to read a large message... but + // that is not necessary right now + } else if (_interruptState == COAX_INTERRUPT_STATE_ERROR) { + Debug::trap(103, "error = %d", _error); + + count = (-1) * _error; + } + + _interruptState = COAX_INTERRUPT_STATE_IDLE; + + return count; +} + +void Coax::handleInterrupt() +{ + if (!_isInitialized) { + Debug::trap(104); + return; + } + + if (_interruptState != COAX_INTERRUPT_STATE_IDLE) { + Debug::trap(105, "state = %d", _interruptState); + return; + } + + _interruptState = COAX_INTERRUPT_STATE_RECEIVING; + + int error = 0; + + uint16_t *buffer = const_cast(_buffer); + size_t bufferSize = _bufferSize; + int bufferCount = 0; + + bool isActive; + int count; + + do { + // Determine if the receiver is active before reading from the FIFO to + // avoid a race condition where the FIFO is empty, the receiver is + // active but is inactive by the time we check the status. + isActive = _spiCoaxTransceiver.isRXActive(); + + // TODO: need to somehow handle an overflow detection here... + + count = _spiCoaxTransceiver.receive(buffer, bufferSize); + + if (count < 0) { + error = (-1) * count; + break; + } + + bufferCount += count; + + buffer += count; + bufferSize -= count; + } while (isActive || count == static_cast(bufferSize)); + + if (error != 0) { + _bufferCount = 0; + _error = error; + + _interruptState = COAX_INTERRUPT_STATE_ERROR; + } else { + _bufferCount = bufferCount; + _error = 0; + + _interruptState = COAX_INTERRUPT_STATE_RECEIVED; + } +} + +#define COAX_COMMAND_READ_REGISTER 0x2 +#define COAX_COMMAND_WRITE_REGISTER 0x3 +#define COAX_COMMAND_TX 0x4 +#define COAX_COMMAND_RX 0x5 +#define COAX_COMMAND_RESET 0xff + +#define NOP asm volatile("nop\n\t") +#define ATOMIC_BLOCK_START __disable_irq() +#define ATOMIC_BLOCK_END __enable_irq() + +SPICoaxTransceiver::SPICoaxTransceiver() +{ +} + +bool SPICoaxTransceiver::init() +{ + // Configure GPIO. + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + + HAL_GPIO_WritePin(GPIOA, ICE40_CS_Pin | COAX_RESET_Pin, GPIO_PIN_RESET); + + GPIO_InitTypeDef gpioInit = { 0 }; + + gpioInit.Pin = ICE40_CS_Pin | COAX_RESET_Pin; + gpioInit.Mode = GPIO_MODE_OUTPUT_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(GPIOA, &gpioInit); + + gpioInit.Pin = COAX_IRQ_Pin; + gpioInit.Mode = GPIO_MODE_IT_RISING; + gpioInit.Pull = GPIO_NOPULL; + + HAL_GPIO_Init(GPIOB, &gpioInit); + + HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); + + // Set initial GPIO state. + HAL_GPIO_WritePin(GPIOA, ICE40_CS_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(GPIOA, COAX_RESET_Pin, GPIO_PIN_RESET); + + // Configure SPI. + __HAL_RCC_SPI1_CLK_ENABLE(); + + gpioInit.Pin = ICE40_SCK_Pin | ICE40_SDI_Pin | ICE40_SDO_Pin; + gpioInit.Mode = GPIO_MODE_AF_PP; + gpioInit.Alternate = GPIO_AF5_SPI1; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + + HAL_GPIO_Init(GPIOA, &gpioInit); + + LL_SPI_InitTypeDef spiInit = { 0 }; + + spiInit.TransferDirection = LL_SPI_FULL_DUPLEX; + spiInit.Mode = LL_SPI_MODE_MASTER; + spiInit.DataWidth = LL_SPI_DATAWIDTH_8BIT; + spiInit.ClockPolarity = LL_SPI_POLARITY_LOW; + spiInit.ClockPhase = LL_SPI_PHASE_1EDGE; + spiInit.NSS = LL_SPI_NSS_SOFT; + spiInit.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; + spiInit.BitOrder = LL_SPI_MSB_FIRST; + spiInit.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; + spiInit.CRCPoly = 7; + + LL_SPI_Init(SPI1, &spiInit); + + LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA); + LL_SPI_DisableNSSPulseMgt(SPI1); + LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER); + + LL_SPI_Enable(SPI1); + + // Release hardware reset. + HAL_GPIO_WritePin(GPIOA, COAX_RESET_Pin, GPIO_PIN_SET); + + uint8_t deviceId = readRegister(COAX_REGISTER_DEVICE_ID); + + if (deviceId != 0xa5) { + return false; + } + + reset(); + + setLoopback(false); + + setTXParity(CoaxParity::Even); + setRXParity(CoaxParity::Even); + + return true; +} + +void SPICoaxTransceiver::reset() +{ + uint8_t transmitBuffer[1] = { COAX_COMMAND_RESET }; + + ATOMIC_BLOCK_START; + LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + + spiTransfer(transmitBuffer, NULL, 1); + + LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + ATOMIC_BLOCK_END; +} + +uint8_t SPICoaxTransceiver::readRegister(uint8_t index) +{ + uint8_t transmitBuffer[2] = { (uint8_t) (COAX_COMMAND_READ_REGISTER | (index << 4)), 0x00 }; + uint8_t receiveBuffer[2]; + + ATOMIC_BLOCK_START; + LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + + spiTransfer(transmitBuffer, receiveBuffer, 2); + + LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + ATOMIC_BLOCK_END; + + return receiveBuffer[1]; +} + +void SPICoaxTransceiver::writeRegister(uint8_t index, uint8_t value, uint8_t mask) +{ + uint8_t transmitBuffer[3] = { (uint8_t) (COAX_COMMAND_WRITE_REGISTER | (index << 4)), mask, value }; + + ATOMIC_BLOCK_START; + LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + + spiTransfer(transmitBuffer, NULL, 3); + + LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + ATOMIC_BLOCK_END; +} + +int SPICoaxTransceiver::transmit(const uint16_t *buffer, size_t bufferCount) +{ + uint8_t transmitBuffer[2] = { COAX_COMMAND_TX }; + uint8_t receiveBuffer[2]; + + size_t count = 0; + int error = 0; + + ATOMIC_BLOCK_START; + LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + + spiTransfer(transmitBuffer, NULL, 1); + + do { + transmitBuffer[0] = (buffer[count] >> 8) & 0x03; + transmitBuffer[1] = buffer[count] & 0xff; + + spiTransfer(transmitBuffer, receiveBuffer, 2); + + uint8_t value = receiveBuffer[1]; + + if (value == 0) { + count++; + } else if (value == 0x81) { + // Overflow... we'll just try again. + continue; + } else if (value == 0x82) { + error = COAX_ERROR_TX_UNDERFLOW; + break; + } + } while (count < bufferCount); + + LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + ATOMIC_BLOCK_END; + + if (error != 0) { + return error; + } + + while (!isTXComplete()) { + NOP; + } + + return count; +} + +int SPICoaxTransceiver::receive(uint16_t *buffer, size_t bufferSize) +{ + uint8_t transmitBuffer[2] = { COAX_COMMAND_RX }; + uint8_t receiveBuffer[2]; + + size_t count = 0; + int error = 0; + + ATOMIC_BLOCK_START; + LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + + spiTransfer(transmitBuffer, NULL, 1); + + transmitBuffer[0] = 0x00; + transmitBuffer[1] = 0x00; + + do { + spiTransfer(transmitBuffer, receiveBuffer, 2); + + uint16_t value = (receiveBuffer[0] << 8) | receiveBuffer[1]; + + if (value & 0x8000) { + error = (-1) * (value & 0x03ff); + + if (error == 0) { + Debug::trap(106); + + error = COAX_ERROR_RX_UNKNOWN; + } + + break; + } else if (value & 0x4000) { + break; + } + + // TODO: can this ever happen... I don't think so now the loop has + // been rewritten. + if (count >= bufferSize) { + Debug::trap(107); + break; + } + + buffer[count] = value & 0x03ff; + + count++; + } while (count < bufferSize); + + LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin); + ATOMIC_BLOCK_END; + + if (error != 0) { + return error; + } + + return count; +} + +void SPICoaxTransceiver::setLoopback(bool loopback) +{ + writeRegister(COAX_REGISTER_CONTROL, loopback ? COAX_REGISTER_CONTROL_LOOPBACK : 0, COAX_REGISTER_CONTROL_LOOPBACK); +} + +void SPICoaxTransceiver::setTXParity(CoaxParity parity) +{ + writeRegister(COAX_REGISTER_CONTROL, parity == CoaxParity::Even ? COAX_REGISTER_CONTROL_TX_PARITY : 0, COAX_REGISTER_CONTROL_TX_PARITY); +} + +void SPICoaxTransceiver::setRXParity(CoaxParity parity) +{ + writeRegister(COAX_REGISTER_CONTROL, parity == CoaxParity::Even ? COAX_REGISTER_CONTROL_RX_PARITY : 0, COAX_REGISTER_CONTROL_RX_PARITY); +} + +void SPICoaxTransceiver::spiTransfer(const uint8_t *transmitBuffer, + uint8_t *receiveBuffer, size_t count) +{ + // TODO: flush, or confirm TX ready? + + for (size_t index = 0; index < count; index++) { + while (!(SPI1->SR & SPI_SR_TXE)) { + NOP; + } + + LL_SPI_TransmitData8(SPI1, transmitBuffer[index]); + + while (!LL_SPI_IsActiveFlag_RXNE(SPI1)) { + NOP; + } + + uint8_t value = LL_SPI_ReceiveData8(SPI1); + + if (receiveBuffer != NULL) { + receiveBuffer[index] = value; + } + } +} diff --git a/interface2/firmware/src/cubemx/startup_stm32l443xx.s b/interface2/firmware/src/cubemx/startup_stm32l443xx.s new file mode 100644 index 0000000..8437e0b --- /dev/null +++ b/interface2/firmware/src/cubemx/startup_stm32l443xx.s @@ -0,0 +1,468 @@ +/** + ****************************************************************************** + * @file startup_stm32l443xx.s + * @author MCD Application Team + * @brief STM32L443xx devices vector table for GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address, + * - Configure the clock system + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under 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: + * opensource.org/licenses/Apache-2.0 + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + +.equ BootRAM, 0xF1E0F85F +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* Set stack pointer */ + +/* Call the clock system initialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + +LoopForever: + b LoopForever + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_PVM_IRQHandler + .word TAMP_STAMP_IRQHandler + .word RTC_WKUP_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_IRQHandler + .word CAN1_TX_IRQHandler + .word CAN1_RX0_IRQHandler + .word CAN1_RX1_IRQHandler + .word CAN1_SCE_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_TIM15_IRQHandler + .word TIM1_UP_TIM16_IRQHandler + .word TIM1_TRG_COM_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word 0 + .word 0 + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C2_EV_IRQHandler + .word I2C2_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word USART2_IRQHandler + .word USART3_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SDMMC1_IRQHandler + .word 0 + .word SPI3_IRQHandler + .word 0 + .word 0 + .word TIM6_DAC_IRQHandler + .word TIM7_IRQHandler + .word DMA2_Channel1_IRQHandler + .word DMA2_Channel2_IRQHandler + .word DMA2_Channel3_IRQHandler + .word DMA2_Channel4_IRQHandler + .word DMA2_Channel5_IRQHandler + .word 0 + .word 0 + .word 0 + .word COMP_IRQHandler + .word LPTIM1_IRQHandler + .word LPTIM2_IRQHandler + .word USB_IRQHandler + .word DMA2_Channel6_IRQHandler + .word DMA2_Channel7_IRQHandler + .word LPUART1_IRQHandler + .word QUADSPI_IRQHandler + .word I2C3_EV_IRQHandler + .word I2C3_ER_IRQHandler + .word SAI1_IRQHandler + .word 0 + .word SWPMI1_IRQHandler + .word TSC_IRQHandler + .word LCD_IRQHandler + .word AES_IRQHandler + .word RNG_IRQHandler + .word FPU_IRQHandler + .word CRS_IRQHandler + + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_IRQHandler + .thumb_set ADC1_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_IRQHandler + .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak USB_IRQHandler + .thumb_set USB_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak AES_IRQHandler + .thumb_set AES_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/stm32l4xx_hal_msp.c b/interface2/firmware/src/cubemx/stm32l4xx_hal_msp.c new file mode 100644 index 0000000..e88b0c1 --- /dev/null +++ b/interface2/firmware/src/cubemx/stm32l4xx_hal_msp.c @@ -0,0 +1,84 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : stm32l4xx_hal_msp.c + * Description : This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/stm32l4xx_it.c b/interface2/firmware/src/cubemx/stm32l4xx_it.c new file mode 100644 index 0000000..d97dac4 --- /dev/null +++ b/interface2/firmware/src/cubemx/stm32l4xx_it.c @@ -0,0 +1,246 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32l4xx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "stm32l4xx_it.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ +extern PCD_HandleTypeDef hpcd_USB_FS; +extern TIM_HandleTypeDef htim6; +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex-M4 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Prefetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ + /* USER CODE BEGIN SVCall_IRQn 0 */ + + /* USER CODE END SVCall_IRQn 0 */ + /* USER CODE BEGIN SVCall_IRQn 1 */ + + /* USER CODE END SVCall_IRQn 1 */ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ + /* USER CODE BEGIN PendSV_IRQn 0 */ + + /* USER CODE END PendSV_IRQn 0 */ + /* USER CODE BEGIN PendSV_IRQn 1 */ + + /* USER CODE END PendSV_IRQn 1 */ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ + /* USER CODE BEGIN SysTick_IRQn 0 */ + + /* USER CODE END SysTick_IRQn 0 */ + HAL_IncTick(); + /* USER CODE BEGIN SysTick_IRQn 1 */ + + /* USER CODE END SysTick_IRQn 1 */ +} + +/******************************************************************************/ +/* STM32L4xx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32l4xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles EXTI line0 interrupt. + */ +void EXTI0_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI0_IRQn 0 */ + + /* USER CODE END EXTI0_IRQn 0 */ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); + /* USER CODE BEGIN EXTI0_IRQn 1 */ + + /* USER CODE END EXTI0_IRQn 1 */ +} + +/** + * @brief This function handles TIM6 global interrupt, DAC channel1 and channel2 underrun error interrupts. + */ +void TIM6_DAC_IRQHandler(void) +{ + /* USER CODE BEGIN TIM6_DAC_IRQn 0 */ + + /* USER CODE END TIM6_DAC_IRQn 0 */ + HAL_TIM_IRQHandler(&htim6); + /* USER CODE BEGIN TIM6_DAC_IRQn 1 */ + + /* USER CODE END TIM6_DAC_IRQn 1 */ +} + +/** + * @brief This function handles USB event interrupt through EXTI line 17. + */ +void USB_IRQHandler(void) +{ + /* USER CODE BEGIN USB_IRQn 0 */ + + /* USER CODE END USB_IRQn 0 */ + HAL_PCD_IRQHandler(&hpcd_USB_FS); + /* USER CODE BEGIN USB_IRQn 1 */ + + /* USER CODE END USB_IRQn 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/system_stm32l4xx.c b/interface2/firmware/src/cubemx/system_stm32l4xx.c new file mode 100644 index 0000000..045a81d --- /dev/null +++ b/interface2/firmware/src/cubemx/system_stm32l4xx.c @@ -0,0 +1,354 @@ +/** + ****************************************************************************** + * @file system_stm32l4xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32l4xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * After each device reset the MSI (4 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32l4xx.s" file, to + * configure the system clock before to branch to main program. + * + * This file configures the system clock as follows: + *============================================================================= + *----------------------------------------------------------------------------- + * System Clock source | MSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * PLL_M | 1 + *----------------------------------------------------------------------------- + * PLL_N | 8 + *----------------------------------------------------------------------------- + * PLL_P | 7 + *----------------------------------------------------------------------------- + * PLL_Q | 2 + *----------------------------------------------------------------------------- + * PLL_R | 2 + *----------------------------------------------------------------------------- + * PLLSAI1_P | NA + *----------------------------------------------------------------------------- + * PLLSAI1_Q | NA + *----------------------------------------------------------------------------- + * PLLSAI1_R | NA + *----------------------------------------------------------------------------- + * PLLSAI2_P | NA + *----------------------------------------------------------------------------- + * PLLSAI2_Q | NA + *----------------------------------------------------------------------------- + * PLLSAI2_R | NA + *----------------------------------------------------------------------------- + * Require 48MHz for USB OTG FS, | Disabled + * SDIO and RNG clock | + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under 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: + * opensource.org/licenses/Apache-2.0 + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32l4xx_system + * @{ + */ + +/** @addtogroup STM32L4xx_System_Private_Includes + * @{ + */ + +#include "stm32l4xx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (MSI_VALUE) + #define MSI_VALUE 4000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_Defines + * @{ + */ + +/************************* Miscellaneous Configuration ************************/ +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/******************************************************************************/ +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_Variables + * @{ + */ + /* The SystemCoreClock variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 4000000U; + + const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U}; + const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; + const uint32_t MSIRangeTable[12] = {100000U, 200000U, 400000U, 800000U, 1000000U, 2000000U, \ + 4000000U, 8000000U, 16000000U, 24000000U, 32000000U, 48000000U}; +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32L4xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * @param None + * @retval None + */ +extern uint32_t bootMagic; + +void SystemInit(void) +{ + // Enter the DFU bootloader if the magic flag is set. + if (bootMagic == 0x32703270) { + bootMagic = 0x00000000; + + uint32_t address = 0x1fff0000; + + void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *) (address + 4))); + + __set_MSP(*(uint32_t *) address); + + bootloader(); + + while (1) { + } + } + + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000U; + + /* Reset HSEON, CSSON , HSION, and PLLON bits */ + RCC->CR &= 0xEAF6FFFFU; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x00001000U; + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + + /* Disable all interrupts */ + RCC->CIER = 0x00000000U; + + /* Configure the Vector Table location add offset address ------------------*/ +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) + * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) MSI_VALUE is a constant defined in stm32l4xx_hal.h file (default value + * 4 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSI_VALUE is a constant defined in stm32l4xx_hal.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (***) HSE_VALUE is a constant defined in stm32l4xx_hal.h file (default value + * 8 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0U, msirange = 0U, pllvco = 0U, pllr = 2U, pllsource = 0U, pllm = 2U; + + /* Get MSI Range frequency--------------------------------------------------*/ + if((RCC->CR & RCC_CR_MSIRGSEL) == RESET) + { /* MSISRANGE from RCC_CSR applies */ + msirange = (RCC->CSR & RCC_CSR_MSISRANGE) >> 8U; + } + else + { /* MSIRANGE from RCC_CR applies */ + msirange = (RCC->CR & RCC_CR_MSIRANGE) >> 4U; + } + /*MSI frequency range in HZ*/ + msirange = MSIRangeTable[msirange]; + + /* Get SYSCLK source -------------------------------------------------------*/ + switch (RCC->CFGR & RCC_CFGR_SWS) + { + case 0x00: /* MSI used as system clock source */ + SystemCoreClock = msirange; + break; + + case 0x04: /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + + case 0x08: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + + case 0x0C: /* PLL used as system clock source */ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN + SYSCLK = PLL_VCO / PLLR + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); + pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> 4U) + 1U ; + + switch (pllsource) + { + case 0x02: /* HSI used as PLL clock source */ + pllvco = (HSI_VALUE / pllm); + break; + + case 0x03: /* HSE used as PLL clock source */ + pllvco = (HSE_VALUE / pllm); + break; + + default: /* MSI used as PLL clock source */ + pllvco = (msirange / pllm); + break; + } + pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 8U); + pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 25U) + 1U) * 2U; + SystemCoreClock = pllvco/pllr; + break; + + default: + SystemCoreClock = msirange; + break; + } + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/tim.c b/interface2/firmware/src/cubemx/tim.c new file mode 100644 index 0000000..f7d5d31 --- /dev/null +++ b/interface2/firmware/src/cubemx/tim.c @@ -0,0 +1,95 @@ +/** + ****************************************************************************** + * File Name : TIM.c + * Description : This file provides code for the configuration + * of the TIM instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "tim.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +TIM_HandleTypeDef htim6; + +/* TIM6 init function */ +void MX_TIM6_Init(void) +{ + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + htim6.Instance = TIM6; + htim6.Init.Prescaler = 8000-1; + htim6.Init.CounterMode = TIM_COUNTERMODE_UP; + htim6.Init.Period = 1000-1; + htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim6) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM6) + { + /* USER CODE BEGIN TIM6_MspInit 0 */ + + /* USER CODE END TIM6_MspInit 0 */ + /* TIM6 clock enable */ + __HAL_RCC_TIM6_CLK_ENABLE(); + + /* TIM6 interrupt Init */ + HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); + /* USER CODE BEGIN TIM6_MspInit 1 */ + + /* USER CODE END TIM6_MspInit 1 */ + } +} + +void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM6) + { + /* USER CODE BEGIN TIM6_MspDeInit 0 */ + + /* USER CODE END TIM6_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM6_CLK_DISABLE(); + + /* TIM6 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn); + /* USER CODE BEGIN TIM6_MspDeInit 1 */ + + /* USER CODE END TIM6_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/usb_device.c b/interface2/firmware/src/cubemx/usb_device.c new file mode 100644 index 0000000..f3d0510 --- /dev/null +++ b/interface2/firmware/src/cubemx/usb_device.c @@ -0,0 +1,102 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usb_device.c + * @version : v2.0_Cube + * @brief : This file implements the USB Device + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ + +#include "usb_device.h" +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_cdc.h" +#include "usbd_cdc_if.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/* USER CODE BEGIN PFP */ +/* Private function prototypes -----------------------------------------------*/ + +/* USER CODE END PFP */ + +/* USB Device Core handle declaration. */ +USBD_HandleTypeDef hUsbDeviceFS; +extern USBD_DescriptorsTypeDef FS_Desc; + +/* + * -- Insert your variables declaration here -- + */ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* + * -- Insert your external function declaration here -- + */ +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * Init USB device Library, add supported class and start the library + * @retval None + */ +void MX_USB_DEVICE_Init(void) +{ + /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */ + + /* USER CODE END USB_DEVICE_Init_PreTreatment */ + + /* Init Device Library, add supported class and start the library. */ + if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK) + { + Error_Handler(); + } + if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) + { + Error_Handler(); + } + if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) + { + Error_Handler(); + } + if (USBD_Start(&hUsbDeviceFS) != USBD_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */ + + /* USER CODE END USB_DEVICE_Init_PostTreatment */ +} + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/usbd_cdc_if.c b/interface2/firmware/src/cubemx/usbd_cdc_if.c new file mode 100644 index 0000000..d433e41 --- /dev/null +++ b/interface2/firmware/src/cubemx/usbd_cdc_if.c @@ -0,0 +1,336 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_cdc_if.c + * @version : v2.0_Cube + * @brief : Usb device for Virtual Com Port. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc_if.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @brief Usb device library. + * @{ + */ + +/** @addtogroup USBD_CDC_IF + * @{ + */ + +/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions + * @brief Private types. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_TYPES */ + +extern void handleMessageData(const uint8_t *buffer, size_t bufferCount); + +/* USER CODE END PRIVATE_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines + * @brief Private defines. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_DEFINES */ +/* USER CODE END PRIVATE_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros + * @brief Private macros. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_MACRO */ + +/* USER CODE END PRIVATE_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables + * @brief Private variables. + * @{ + */ +/* Create buffer for reception and transmission */ +/* It's up to user to redefine and/or remove those define */ +/** Received data over USB are stored in this buffer */ +uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; + +/** Data to send over USB CDC are stored in this buffer */ +uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; + +/* USER CODE BEGIN PRIVATE_VARIABLES */ + +/* USER CODE END PRIVATE_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables + * @brief Public variables. + * @{ + */ + +extern USBD_HandleTypeDef hUsbDeviceFS; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes + * @brief Private functions declaration. + * @{ + */ + +static int8_t CDC_Init_FS(void); +static int8_t CDC_DeInit_FS(void); +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); +static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); +static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum); + +/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */ + +/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ + +/** + * @} + */ + +USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = +{ + CDC_Init_FS, + CDC_DeInit_FS, + CDC_Control_FS, + CDC_Receive_FS, + CDC_TransmitCplt_FS +}; + +/* Private functions ---------------------------------------------------------*/ +/** + * @brief Initializes the CDC media low layer over the FS USB IP + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Init_FS(void) +{ + /* USER CODE BEGIN 3 */ + /* Set Application Buffers */ + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + return (USBD_OK); + /* USER CODE END 3 */ +} + +/** + * @brief DeInitializes the CDC media low layer + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_DeInit_FS(void) +{ + /* USER CODE BEGIN 4 */ + return (USBD_OK); + /* USER CODE END 4 */ +} + +/** + * @brief Manage the CDC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) +{ + /* USER CODE BEGIN 5 */ + switch(cmd) + { + case CDC_SEND_ENCAPSULATED_COMMAND: + + break; + + case CDC_GET_ENCAPSULATED_RESPONSE: + + break; + + case CDC_SET_COMM_FEATURE: + + break; + + case CDC_GET_COMM_FEATURE: + + break; + + case CDC_CLEAR_COMM_FEATURE: + + break; + + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 0 - 1 Stop bit */ + /* 1 - 1.5 Stop bits */ + /* 2 - 2 Stop bits */ + /* 5 | bParityType | 1 | Number | Parity */ + /* 0 - None */ + /* 1 - Odd */ + /* 2 - Even */ + /* 3 - Mark */ + /* 4 - Space */ + /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ + /*******************************************************************************/ + case CDC_SET_LINE_CODING: + + break; + + case CDC_GET_LINE_CODING: + + break; + + case CDC_SET_CONTROL_LINE_STATE: + + break; + + case CDC_SEND_BREAK: + + break; + + default: + break; + } + + return (USBD_OK); + /* USER CODE END 5 */ +} + +/** + * @brief Data received over USB OUT endpoint are sent over CDC interface + * through this function. + * + * @note + * This function will issue a NAK packet on any OUT packet received on + * USB endpoint until exiting this function. If you exit this function + * before transfer is complete on CDC interface (ie. using DMA controller) + * it will result in receiving more data while previous ones are still + * not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) +{ + /* USER CODE BEGIN 6 */ + handleMessageData(Buf, *Len); + + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + + return (USBD_OK); + /* USER CODE END 6 */ +} + +/** + * @brief CDC_Transmit_FS + * Data to send over USB IN endpoint are sent over CDC interface + * through this function. + * @note + * + * + * @param Buf: Buffer of data to be sent + * @param Len: Number of data to be sent (in bytes) + * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY + */ +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) +{ + uint8_t result = USBD_OK; + /* USER CODE BEGIN 7 */ + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; + if (hcdc->TxState != 0){ + return USBD_BUSY; + } + memcpy(UserTxBufferFS, Buf, Len); + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); + result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); + /* USER CODE END 7 */ + return result; +} + +/** + * @brief CDC_TransmitCplt_FS + * Data transmited callback + * + * @note + * This function is IN transfer complete callback used to inform user that + * the submitted Data is successfully sent over USB. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) +{ + uint8_t result = USBD_OK; + /* USER CODE BEGIN 13 */ + UNUSED(Buf); + UNUSED(Len); + UNUSED(epnum); + /* USER CODE END 13 */ + return result; +} + +/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */ + +/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/usbd_conf.c b/interface2/firmware/src/cubemx/usbd_conf.c new file mode 100644 index 0000000..f8d452c --- /dev/null +++ b/interface2/firmware/src/cubemx/usbd_conf.c @@ -0,0 +1,828 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : Target/usbd_conf.c + * @version : v2.0_Cube + * @brief : This file implements the board support package for the USB device library + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx.h" +#include "stm32l4xx_hal.h" +#include "usbd_def.h" +#include "usbd_core.h" +#include "usbd_cdc.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +PCD_HandleTypeDef hpcd_USB_FS; +void Error_Handler(void); + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* Exported function prototypes ----------------------------------------------*/ +extern USBD_StatusTypeDef USBD_LL_BatteryCharging(USBD_HandleTypeDef *pdev); + +/* USER CODE BEGIN PFP */ +/* Private function prototypes -----------------------------------------------*/ + +/* USER CODE END PFP */ + +/* Private functions ---------------------------------------------------------*/ + +/* USER CODE BEGIN 1 */ +static void SystemClockConfig_Resume(void); + +/* USER CODE END 1 */ +extern void SystemClock_Config(void); + +/******************************************************************************* + LL Driver Callbacks (PCD -> USB Device Library) +*******************************************************************************/ +/* MSP Init */ + +void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) +{ + if(pcdHandle->Instance==USB) + { + /* USER CODE BEGIN USB_MspInit 0 */ + + /* USER CODE END USB_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_USB_CLK_ENABLE(); + + /* Peripheral interrupt init */ + HAL_NVIC_SetPriority(USB_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USB_IRQn); + /* USER CODE BEGIN USB_MspInit 1 */ + + /* USER CODE END USB_MspInit 1 */ + } +} + +void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) +{ + if(pcdHandle->Instance==USB) + { + /* USER CODE BEGIN USB_MspDeInit 0 */ + + /* USER CODE END USB_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USB_CLK_DISABLE(); + + /* Peripheral interrupt Deinit*/ + HAL_NVIC_DisableIRQ(USB_IRQn); + + /* USER CODE BEGIN USB_MspDeInit 1 */ + + /* USER CODE END USB_MspDeInit 1 */ + } +} + +/** + * @brief Setup stage callback + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup); +} + +/** + * @brief Data Out stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); +} + +/** + * @brief Data In stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); +} + +/** + * @brief SOF callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData); +} + +/** + * @brief Reset callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_SpeedTypeDef speed = USBD_SPEED_FULL; + + if ( hpcd->Init.speed != PCD_SPEED_FULL) + { + Error_Handler(); + } + /* Set Speed. */ + USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed); + + /* Reset Device. */ + USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData); +} + +/** + * @brief Suspend callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* Inform USB library that core enters in suspend Mode. */ + USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData); + /* Enter in STOP mode. */ + /* USER CODE BEGIN 2 */ + if (hpcd->Init.low_power_enable) + { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + /* USER CODE END 2 */ +} + +/** + * @brief Resume callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + + /* USER CODE BEGIN 3 */ + if (hpcd->Init.low_power_enable) + { + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + SystemClockConfig_Resume(); + } + /* USER CODE END 3 */ + USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData); +} + +/** + * @brief ISOOUTIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); +} + +/** + * @brief ISOINIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); +} + +/** + * @brief Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData); +} + +/** + * @brief Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData); +} + +/******************************************************************************* + LL Driver Interface (USB Device Library --> PCD) +*******************************************************************************/ + +/** + * @brief Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) +{ + /* Init USB Ip. */ + /* Enable USB power on Pwrctrl CR2 register. */ + HAL_PWREx_EnableVddUSB(); + /* Link the driver to the stack. */ + hpcd_USB_FS.pData = pdev; + pdev->pData = &hpcd_USB_FS; + + hpcd_USB_FS.Instance = USB; + hpcd_USB_FS.Init.dev_endpoints = 8; + hpcd_USB_FS.Init.speed = PCD_SPEED_FULL; + hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd_USB_FS.Init.Sof_enable = DISABLE; + hpcd_USB_FS.Init.low_power_enable = DISABLE; + hpcd_USB_FS.Init.lpm_enable = DISABLE; + hpcd_USB_FS.Init.battery_charging_enable = DISABLE; + if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) + { + Error_Handler( ); + } + +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) + /* Register USB PCD CallBacks */ + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback); + + HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_FS, PCD_DataOutStageCallback); + HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_FS, PCD_DataInStageCallback); + HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_FS, PCD_ISOOUTIncompleteCallback); + HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_FS, PCD_ISOINIncompleteCallback); +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ + /* USER CODE BEGIN EndPoint_Configuration */ + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); + /* USER CODE END EndPoint_Configuration */ + /* USER CODE BEGIN EndPoint_Configuration_CDC */ + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100); + /* USER CODE END EndPoint_Configuration_CDC */ + return USBD_OK; +} + +/** + * @brief De-Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_DeInit(pdev->pData); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Starts the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Start(pdev->pData); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Stops the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Stop(pdev->pData); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Opens an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param ep_type: Endpoint type + * @param ep_mps: Endpoint max packet size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Closes an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Flushes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Sets a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Clears a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Returns Stall condition. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Stall (1: Yes, 0: No) + */ +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData; + + if((ep_addr & 0x80) == 0x80) + { + return hpcd->IN_ep[ep_addr & 0x7F].is_stall; + } + else + { + return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; + } +} + +/** + * @brief Assigns a USB address to the device. + * @param pdev: Device handle + * @param dev_addr: Device address + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Transmits data over an endpoint. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be sent + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Prepares an endpoint for reception. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be received + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); + + switch (hal_status) { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} + +/** + * @brief Returns the last transfered packet size. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Recived Data Size + */ +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr); +} + +/** + * @brief Send LPM message to user layer + * @param hpcd: PCD handle + * @param msg: LPM message + * @retval None + */ +void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) +{ + switch (msg) + { + case PCD_LPM_L0_ACTIVE: + if (hpcd->Init.low_power_enable) + { + SystemClockConfig_Resume(); + + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + USBD_LL_Resume(hpcd->pData); + break; + + case PCD_LPM_L1_ACTIVE: + USBD_LL_Suspend(hpcd->pData); + + /* Enter in STOP mode. */ + if (hpcd->Init.low_power_enable) + { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + break; + } +} + +/** + * @brief Delays routine for the USB Device Library. + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @brief Static single allocation. + * @param size: Size of allocated memory + * @retval None + */ +void *USBD_static_malloc(uint32_t size) +{ + static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */ + return mem; +} + +/** + * @brief Dummy memory free + * @param p: Pointer to allocated memory address + * @retval None + */ +void USBD_static_free(void *p) +{ + +} + +/* USER CODE BEGIN 5 */ +/** + * @brief Configures system clock after wake-up from USB resume callBack: + * enable HSI, PLL and select PLL as system clock source. + * @retval None + */ +static void SystemClockConfig_Resume(void) +{ + SystemClock_Config(); +} +/* USER CODE END 5 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/cubemx/usbd_desc.c b/interface2/firmware/src/cubemx/usbd_desc.c new file mode 100644 index 0000000..5108e47 --- /dev/null +++ b/interface2/firmware/src/cubemx/usbd_desc.c @@ -0,0 +1,445 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : App/usbd_desc.c + * @version : v2.0_Cube + * @brief : This file implements the USB device descriptors. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_conf.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @addtogroup USBD_DESC + * @{ + */ + +/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions + * @brief Private types. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_TYPES */ + +/* USER CODE END PRIVATE_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines + * @brief Private defines. + * @{ + */ + +#define USBD_VID 1155 +#define USBD_LANGID_STRING 1033 +#define USBD_MANUFACTURER_STRING "STMicroelectronics" +#define USBD_PID_FS 22336 +#define USBD_PRODUCT_STRING_FS "STM32 Virtual ComPort" +#define USBD_CONFIGURATION_STRING_FS "CDC Config" +#define USBD_INTERFACE_STRING_FS "CDC Interface" + +#define USB_SIZ_BOS_DESC 0x0C + +/* USER CODE BEGIN PRIVATE_DEFINES */ + +/* USER CODE END PRIVATE_DEFINES */ + +/** + * @} + */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros + * @brief Private macros. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_MACRO */ + +/* USER CODE END PRIVATE_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes + * @brief Private functions declaration. + * @{ + */ + +static void Get_SerialNum(void); +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len); + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes + * @brief Private functions declaration for FS. + * @{ + */ + +uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +#if (USBD_LPM_ENABLED == 1) +uint8_t * USBD_FS_USR_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +#endif /* (USBD_LPM_ENABLED == 1) */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables + * @brief Private variables. + * @{ + */ + +USBD_DescriptorsTypeDef FS_Desc = +{ + USBD_FS_DeviceDescriptor +, USBD_FS_LangIDStrDescriptor +, USBD_FS_ManufacturerStrDescriptor +, USBD_FS_ProductStrDescriptor +, USBD_FS_SerialStrDescriptor +, USBD_FS_ConfigStrDescriptor +, USBD_FS_InterfaceStrDescriptor +#if (USBD_LPM_ENABLED == 1) +, USBD_FS_USR_BOSDescriptor +#endif /* (USBD_LPM_ENABLED == 1) */ +}; + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ +/** USB standard device descriptor. */ +__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = +{ + 0x12, /*bLength */ + USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ +#if (USBD_LPM_ENABLED == 1) + 0x01, /*bcdUSB */ /* changed to USB version 2.01 + in order to support LPM L1 suspend + resume test of USBCV3.0*/ +#else + 0x00, /*bcdUSB */ +#endif /* (USBD_LPM_ENABLED == 1) */ + 0x02, + 0x02, /*bDeviceClass*/ + 0x02, /*bDeviceSubClass*/ + 0x00, /*bDeviceProtocol*/ + USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ + LOBYTE(USBD_VID), /*idVendor*/ + HIBYTE(USBD_VID), /*idVendor*/ + LOBYTE(USBD_PID_FS), /*idProduct*/ + HIBYTE(USBD_PID_FS), /*idProduct*/ + 0x00, /*bcdDevice rel. 2.00*/ + 0x02, + USBD_IDX_MFC_STR, /*Index of manufacturer string*/ + USBD_IDX_PRODUCT_STR, /*Index of product string*/ + USBD_IDX_SERIAL_STR, /*Index of serial number string*/ + USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ +}; + +/* USB_DeviceDescriptor */ +/** BOS descriptor. */ +#if (USBD_LPM_ENABLED == 1) +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ +__ALIGN_BEGIN uint8_t USBD_FS_BOSDesc[USB_SIZ_BOS_DESC] __ALIGN_END = +{ + 0x5, + USB_DESC_TYPE_BOS, + 0xC, + 0x0, + 0x1, /* 1 device capability*/ + /* device capability*/ + 0x7, + USB_DEVICE_CAPABITY_TYPE, + 0x2, + 0x2, /* LPM capability bit set*/ + 0x0, + 0x0, + 0x0 +}; +#endif /* (USBD_LPM_ENABLED == 1) */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables + * @brief Private variables. + * @{ + */ + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ + +/** USB lang indentifier descriptor. */ +__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = +{ + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING) +}; + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ +/* Internal string descriptor. */ +__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; + +#if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 +#endif +__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = { + USB_SIZ_STRING_SERIAL, + USB_DESC_TYPE_STRING, +}; + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions + * @brief Private functions. + * @{ + */ + +/** + * @brief Return the device descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = sizeof(USBD_FS_DeviceDesc); + return USBD_FS_DeviceDesc; +} + +/** + * @brief Return the LangID string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = sizeof(USBD_LangIDDesc); + return USBD_LangIDDesc; +} + +/** + * @brief Return the product string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == 0) + { + USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_PRODUCT_STRING_FS, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Return the manufacturer string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** + * @brief Return the serial number string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = USB_SIZ_STRING_SERIAL; + + /* Update the serial number string descriptor with the data from the unique + * ID */ + Get_SerialNum(); + /* USER CODE BEGIN USBD_FS_SerialStrDescriptor */ + + /* USER CODE END USBD_FS_SerialStrDescriptor */ + return (uint8_t *) USBD_StringSerial; +} + +/** + * @brief Return the configuration string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == USBD_SPEED_HIGH) + { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Return the interface string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == 0) + { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +#if (USBD_LPM_ENABLED == 1) +/** + * @brief Return the BOS descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_FS_USR_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = sizeof(USBD_FS_BOSDesc); + return (uint8_t*)USBD_FS_BOSDesc; +} +#endif /* (USBD_LPM_ENABLED == 1) */ + +/** + * @brief Create the serial number string descriptor + * @param None + * @retval None + */ +static void Get_SerialNum(void) +{ + uint32_t deviceserial0, deviceserial1, deviceserial2; + + deviceserial0 = *(uint32_t *) DEVICE_ID1; + deviceserial1 = *(uint32_t *) DEVICE_ID2; + deviceserial2 = *(uint32_t *) DEVICE_ID3; + + deviceserial0 += deviceserial2; + + if (deviceserial0 != 0) + { + IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8); + IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4); + } +} + +/** + * @brief Convert Hex 32Bits value into char + * @param value: value to convert + * @param pbuf: pointer to the buffer + * @param len: buffer length + * @retval None + */ +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len) +{ + uint8_t idx = 0; + + for (idx = 0; idx < len; idx++) + { + if (((value >> 28)) < 0xA) + { + pbuf[2 * idx] = (value >> 28) + '0'; + } + else + { + pbuf[2 * idx] = (value >> 28) + 'A' - 10; + } + + value = value << 4; + + pbuf[2 * idx + 1] = 0; + } +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/interface2/firmware/src/debug.cpp b/interface2/firmware/src/debug.cpp new file mode 100644 index 0000000..5d3114d --- /dev/null +++ b/interface2/firmware/src/debug.cpp @@ -0,0 +1,142 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +#include "stm32l4xx_hal.h" + +#include "pins.h" + +#include "debug.h" + +UART_HandleTypeDef huart1; + +bool Debug::init() +{ + // Configure UART. + huart1.Instance = USART1; + + huart1.Init.BaudRate = 115200; + huart1.Init.WordLength = UART_WORDLENGTH_8B; + huart1.Init.StopBits = UART_STOPBITS_1; + huart1.Init.Parity = UART_PARITY_NONE; + huart1.Init.Mode = UART_MODE_TX_RX; + huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart1.Init.OverSampling = UART_OVERSAMPLING_16; + huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + + huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + + if (HAL_UART_Init(&huart1) != HAL_OK) { + return false; + } + + // Configure GPIO. + __HAL_RCC_GPIOB_CLK_ENABLE(); + + HAL_GPIO_WritePin(GPIOB, GPIO0_Pin | GPIO1_Pin, GPIO_PIN_RESET); + + GPIO_InitTypeDef gpioInit = { 0 }; + + gpioInit.Pin = GPIO0_Pin | GPIO1_Pin; + gpioInit.Mode = GPIO_MODE_OUTPUT_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(GPIOB, &gpioInit); + + // Set initial GPIO state. + HAL_GPIO_WritePin(GPIOB, GPIO0_Pin | GPIO1_Pin, GPIO_PIN_RESET); + + return true; +} + +void Debug::banner() +{ + printf("\r\n"); + printf("****** Coax\r\n"); + printf(" **** Build " FIRMWARE_BUILD_WHAT " by " FIRMWARE_BUILD_WHO " on " FIRMWARE_BUILD_WHEN "\r\n"); + printf(" **\r\n"); +} + +void Debug::setMarker(int marker) +{ + if (marker == 0) { + HAL_GPIO_WritePin(GPIOB, GPIO0_Pin, GPIO_PIN_SET); + } else if (marker == 1) { + HAL_GPIO_WritePin(GPIOB, GPIO1_Pin, GPIO_PIN_SET); + } +} + +void Debug::resetMarker(int marker) +{ + if (marker == 0) { + HAL_GPIO_WritePin(GPIOB, GPIO0_Pin, GPIO_PIN_RESET); + } else if (marker == 1) { + HAL_GPIO_WritePin(GPIOB, GPIO1_Pin, GPIO_PIN_RESET); + } +} + +void Debug::trap(int number) +{ + printf("%lu TRAP[%d]\r\n", HAL_GetTick(), number); +} + +void Debug::trap(int number, const char *format, ...) +{ + printf("%lu TRAP[%d] ", HAL_GetTick(), number); + + va_list args; + + va_start(args, format); + vprintf(format, args); + va_end(args); + + printf("\r\n"); +} + +extern "C" void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) +{ + GPIO_InitTypeDef gpioInit = { 0 }; + + if (uartHandle->Instance == USART1) { + __HAL_RCC_USART1_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + + gpioInit.Pin = GPIO_PIN_9 | GPIO_PIN_10; + gpioInit.Mode = GPIO_MODE_AF_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpioInit.Alternate = GPIO_AF7_USART1; + + HAL_GPIO_Init(GPIOA, &gpioInit); + } +} + +extern "C" void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) +{ + if (uartHandle->Instance == USART1) { + __HAL_RCC_USART1_CLK_DISABLE(); + + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10); + } +} + +extern "C" int _write(int file, char *ptr, int len) +{ + HAL_UART_Transmit(&huart1, reinterpret_cast(ptr), len, 100); + + return len; +} diff --git a/interface2/firmware/src/ice40.cpp b/interface2/firmware/src/ice40.cpp new file mode 100644 index 0000000..8bc0f5c --- /dev/null +++ b/interface2/firmware/src/ice40.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "pins.h" + +#include "ice40.h" + +ICE40::ICE40() +{ + _isConfigured = false; +} + +inline void clock() +{ + LL_GPIO_ResetOutputPin(ICE40_SCK_GPIO_Port, ICE40_SCK_Pin); + + for (int index = 0; index < 4; index++) { + asm volatile("nop\n\t"); + } + + LL_GPIO_SetOutputPin(ICE40_SCK_GPIO_Port, ICE40_SCK_Pin); +} + +bool ICE40::configure(const uint8_t *bitstream, size_t bitstreamCount) +{ + _isConfigured = false; + + // Configure GPIO. + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + + HAL_GPIO_WritePin(GPIOA, ICE40_CS_Pin | ICE40_SCK_Pin | ICE40_SDI_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOB, ICE40_CRESET_Pin, GPIO_PIN_RESET); + + GPIO_InitTypeDef gpioInit = { 0 }; + + gpioInit.Pin = ICE40_CS_Pin | ICE40_SCK_Pin | ICE40_SDI_Pin; + gpioInit.Mode = GPIO_MODE_OUTPUT_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(GPIOA, &gpioInit); + + gpioInit.Pin = ICE40_CRESET_Pin; + gpioInit.Mode = GPIO_MODE_OUTPUT_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(GPIOB, &gpioInit); + + gpioInit.Pin = ICE40_CDONE_Pin; + gpioInit.Mode = GPIO_MODE_INPUT; + gpioInit.Pull = GPIO_NOPULL; + + HAL_GPIO_Init(GPIOB, &gpioInit); + + // Set initial GPIO state. + HAL_GPIO_WritePin(ICE40_CS_GPIO_Port, ICE40_CS_Pin | ICE40_SCK_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(ICE40_CRESET_GPIO_Port, ICE40_CRESET_Pin, GPIO_PIN_SET); + + // Assert CS and reset. + HAL_GPIO_WritePin(ICE40_CS_GPIO_Port, ICE40_CS_Pin, GPIO_PIN_RESET); + + HAL_GPIO_WritePin(ICE40_CRESET_GPIO_Port, ICE40_CRESET_Pin, GPIO_PIN_RESET); + + HAL_Delay(1); + + HAL_GPIO_WritePin(ICE40_CRESET_GPIO_Port, ICE40_CRESET_Pin, GPIO_PIN_SET); + + HAL_Delay(1); + + // Send the bitstream. + for (size_t index = 0; index < bitstreamCount; index++) { + uint8_t byte = bitstream[index]; + + for (int bitIndex = 7; bitIndex >= 0; bitIndex--) { + if ((byte >> bitIndex) & 0x01) { + LL_GPIO_SetOutputPin(ICE40_SDI_GPIO_Port, ICE40_SDI_Pin); + } else { + LL_GPIO_ResetOutputPin(ICE40_SDI_GPIO_Port, ICE40_SDI_Pin); + } + + clock(); + } + } + + // Check done. + bool done = LL_GPIO_IsInputPinSet(ICE40_CDONE_GPIO_Port, ICE40_CDONE_Pin); + + if (done) { + for (int index = 0; index < 49; index++) { + clock(); + } + } + + // Deassert CS. + HAL_GPIO_WritePin(ICE40_CS_GPIO_Port, ICE40_CS_Pin, GPIO_PIN_SET); + + _isConfigured = done; + + return _isConfigured; +} diff --git a/interface2/firmware/src/indicators.cpp b/interface2/firmware/src/indicators.cpp new file mode 100644 index 0000000..5dec337 --- /dev/null +++ b/interface2/firmware/src/indicators.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "pins.h" + +#include "indicators.h" + +#define LED_GPIO_Port GPIOB + +Indicators::Indicators() +{ + _status = INDICATORS_STATUS_UNKNOWN; + + _txState = 0; + _rxState = 0; + _errorState = 0; +} + +void Indicators::init() +{ + // Configure GPIO. + __HAL_RCC_GPIOB_CLK_ENABLE(); + + HAL_GPIO_WritePin(LED_GPIO_Port, LED_STATUS_Pin | LED_TX_Pin | LED_RX_Pin | LED_ERROR_Pin, GPIO_PIN_RESET); + + GPIO_InitTypeDef gpioInit = { 0 }; + + gpioInit.Pin = LED_STATUS_Pin | LED_TX_Pin | LED_RX_Pin | LED_ERROR_Pin; + gpioInit.Mode = GPIO_MODE_OUTPUT_PP; + gpioInit.Pull = GPIO_NOPULL; + gpioInit.Speed = GPIO_SPEED_FREQ_LOW; + + HAL_GPIO_Init(LED_GPIO_Port, &gpioInit); + + // Set initial GPIO state. + HAL_GPIO_WritePin(LED_GPIO_Port, LED_STATUS_Pin | LED_TX_Pin | LED_RX_Pin | LED_ERROR_Pin, GPIO_PIN_SET); +} + +void Indicators::setStatus(IndicatorsStatus status) +{ + _status = status; + + if (_status == INDICATORS_STATUS_CONFIGURING) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_STATUS_Pin, GPIO_PIN_SET); + + HAL_GPIO_WritePin(LED_GPIO_Port, LED_TX_Pin | LED_RX_Pin | LED_ERROR_Pin, GPIO_PIN_RESET); + } else if (_status == INDICATORS_STATUS_RUNNING) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_STATUS_Pin, GPIO_PIN_SET); + } +} + +void Indicators::tx() +{ + if (_txState == 0) { + _txState = 2; + } +} + +void Indicators::rx() +{ + if (_rxState == 0) { + _rxState = 2; + } +} + +void Indicators::error() +{ + if (_errorState == 0) { + _errorState = 2; + } +} + +void Indicators::update() +{ + if (_status == INDICATORS_STATUS_CONFIGURING) { + HAL_GPIO_TogglePin(LED_GPIO_Port, LED_STATUS_Pin); + } + + if (_txState > 0) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_TX_Pin, _txState == 2 ? GPIO_PIN_SET : GPIO_PIN_RESET); + + _txState--; + } else { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_TX_Pin, GPIO_PIN_RESET); + } + + if (_rxState > 0) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_RX_Pin, _rxState == 2 ? GPIO_PIN_SET : GPIO_PIN_RESET); + + _rxState--; + } else { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_RX_Pin, GPIO_PIN_RESET); + } + + if (_errorState > 0) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_ERROR_Pin, _errorState == 2 ? GPIO_PIN_SET : GPIO_PIN_RESET); + + _errorState--; + } else { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_ERROR_Pin, GPIO_PIN_RESET); + } +} diff --git a/interface2/firmware/src/interface.cpp b/interface2/firmware/src/interface.cpp new file mode 100644 index 0000000..5184b1d --- /dev/null +++ b/interface2/firmware/src/interface.cpp @@ -0,0 +1,279 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +#include + +#include "stm32l4xx_hal.h" + +#include "config.h" +#include "coax.h" +#include "indicators.h" +#include "message.h" +#include "debug.h" +#include "version.h" + +#include "interface.h" + +void sendErrorMessage(uint8_t code, const char *description) +{ + uint8_t message[2 + 62 + 1] = { 0x02, code }; + size_t count = 2; + + if (description != NULL) { + strncpy(reinterpret_cast(message + 2), description, 62); + + count += strlen(description); + } + + MessageSender::send(message, count); +} + +Interface::Interface(Coax &coax, Indicators &indicators) : + _coax(coax), + _indicators(indicators) +{ +} + +void Interface::handleMessage(uint8_t *buffer, size_t bufferCount) +{ + if (bufferCount < 4) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_MESSAGE_BUFFER_COUNT_4"); + return; + } + + size_t count = (buffer[0] << 8) | buffer[1]; + + if (bufferCount - 4 != count) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_MESSAGE_BUFFER_COUNT_MISMATCH"); + return; + } + + if (count < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_COMMAND_BUFFER_COUNT_1"); + return; + } + + uint8_t command = buffer[2]; + + if (command == COMMAND_RESET) { + handleReset(buffer + 3, count - 1); + } else if (command == COMMAND_TRANSMIT_RECEIVE) { + Debug::setMarker(0); + handleTransmitReceive(buffer + 3, count - 1); + Debug::resetMarker(0); + } else if (command == COMMAND_INFO) { + handleInfo(buffer + 3, count - 1); + } else if (command == COMMAND_TEST) { + handleTest(buffer + 3, count - 1); + } else if (command == COMMAND_DFU) { + handleDFU(buffer + 3, count - 1); + } else { + sendErrorMessage(ERROR_UNKNOWN_COMMAND, NULL); + } +} + +void Interface::handleError(MessageReceiverError error) +{ + if (error == MESSAGE_RECEIVER_ERROR_TIMEOUT) { + sendErrorMessage(ERROR_MESSAGE_TIMEOUT, NULL); + } else { + Debug::trap(401, "error = %d", error); + } +} + +void Interface::handleReset(uint8_t *buffer, size_t bufferCount) +{ + _coax.reset(); + + uint8_t response[] = { 0x01, 0x32, 0x70 }; + + MessageSender::send(response, 3); +} + +void Interface::handleTransmitReceive(uint8_t *buffer, size_t bufferCount) +{ + if (bufferCount < 6) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_TXRX_BUFFER_COUNT_6"); + return; + } + + uint16_t *transmitBuffer = reinterpret_cast(buffer + 2); + uint16_t transmitBufferCount = (bufferCount - 6) / 2; + + uint16_t transmitRepeatCount = ((buffer[0] << 8) | buffer[1]) & 0x7fff; + uint16_t transmitRepeatOffset = buffer[0] >> 7; + + uint16_t receiveBufferSize = (buffer[bufferCount - 4] << 8) | buffer[bufferCount - 3]; + uint16_t receiveTimeout = (buffer[bufferCount - 2] << 8) | buffer[bufferCount - 1]; + + if (transmitBufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_TXRX_TX_BUFFER_COUNT_1"); + return; + } + + // Expand the provided data if applicable. + if (transmitRepeatCount > 1) { + uint8_t *source = reinterpret_cast(transmitBuffer) + (transmitRepeatOffset * 2); + uint8_t *destination = reinterpret_cast(transmitBuffer) + (transmitBufferCount * 2); + + uint16_t sourceCount = transmitBufferCount - transmitRepeatOffset; + + size_t length = sourceCount * 2; + + for (int index = 1; index < transmitRepeatCount; index++) { + memcpy(destination, source, length); + + transmitBufferCount += sourceCount; + + destination += length; + } + } + + int transmitCount = _coax.transmit(transmitBuffer, transmitBufferCount); + + if (transmitCount < 0) { + Debug::trap(402, "error = %d", transmitCount); + + _indicators.error(); + + // Convert the error to legacy interface error for compatability. + if (transmitCount == COAX_ERROR_TX_RECEIVER_ACTIVE) { + sendErrorMessage(101, NULL); + } else { + sendErrorMessage(105, NULL); + } + + return; + } + + _indicators.tx(); + + uint16_t *receiveBuffer = reinterpret_cast(buffer + 2); + + int receiveCount = _coax.receive(receiveBuffer, receiveBufferSize, receiveTimeout); + + if (receiveCount < 0) { + Debug::trap(403, "error = %d", receiveCount); + + _indicators.error(); + + // Convert the error to legacy interface error for compatability. + if (receiveCount == COAX_ERROR_RX_LOSS_OF_MID_BIT_TRANSITION) { + sendErrorMessage(104, "Loss of mid bit transition"); + } else if (receiveCount == COAX_ERROR_RX_PARITY) { + sendErrorMessage(104, "Parity error"); + } else if (receiveCount == COAX_ERROR_RX_INVALID_END_SEQUENCE) { + sendErrorMessage(104, "Invalid end sequence"); + } else { + sendErrorMessage(104, NULL); + } + + return; + } + + // Convert timeout to legacy interface error for compatability. + if (receiveCount == 0) { + sendErrorMessage(102, NULL); + return; + } + + _indicators.rx(); + + // Send the response message. + buffer[1] = 0x01; + + MessageSender::send(buffer + 1, 1 + (receiveCount * 2)); +} + +void Interface::handleInfo(uint8_t *buffer, size_t bufferCount) +{ + if (bufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_INFO_BUFFER_COUNT_1"); + return; + } + + uint8_t query = buffer[0]; + + if (query == INFO_SUPPORTED_QUERIES) { + buffer[0] = 0x01; + buffer[1] = INFO_SUPPORTED_QUERIES; + buffer[2] = INFO_HARDWARE_TYPE; + buffer[3] = INFO_FIRMWARE_VERSION; + buffer[4] = INFO_MESSAGE_BUFFER_SIZE; + + MessageSender::send(buffer, 5); + } else if (query == INFO_HARDWARE_TYPE) { + buffer[0] = 0x01; + + int length = snprintf(reinterpret_cast(buffer + 1), 64, "interface2"); + + MessageSender::send(buffer, length + 1); + } else if (query == INFO_FIRMWARE_VERSION) { + buffer[0] = 0x01; + + int length = snprintf(reinterpret_cast(buffer + 1), 64, + "%d.%d.%d (build %s)", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, + FIRMWARE_BUILD_WHAT); + + MessageSender::send(buffer, length + 1); + } else if (query == INFO_MESSAGE_BUFFER_SIZE) { + buffer[0] = 0x01; + + uint32_t size = __htonl(MESSAGE_BUFFER_SIZE); + + memcpy(buffer + 1, &size, sizeof(uint32_t)); + + MessageSender::send(buffer, 5); + } else { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_INFO_UNKNOWN_QUERY"); + return; + } +} + +void Interface::handleTest(uint8_t *buffer, size_t bufferCount) +{ + if (bufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_TEST_BUFFER_COUNT_1"); + return; + } + + uint8_t test = buffer[0]; + + if (test == TEST_SUPPORTED_TESTS) { + buffer[0] = 0x01; + buffer[1] = TEST_SUPPORTED_TESTS; + + MessageSender::send(buffer, 2); + } else { + sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_TEST_UNKNOWN_TEST"); + return; + } +} + +extern void resetToBootloader(); + +void Interface::handleDFU(uint8_t *buffer, size_t bufferCount) +{ + buffer[0] = 0x01; + + MessageSender::send(buffer, 1); + + // Wait before resetting to allow the response to be sent. + HAL_Delay(1000); + + resetToBootloader(); +} diff --git a/interface2/firmware/src/main.cpp b/interface2/firmware/src/main.cpp new file mode 100644 index 0000000..4bcb21d --- /dev/null +++ b/interface2/firmware/src/main.cpp @@ -0,0 +1,209 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include + +#include "tim.h" +#include "usb_device.h" + +#include "pins.h" +#include "config.h" +#include "indicators.h" +#include "ice40.h" +#include "coax.h" +#include "message.h" +#include "interface.h" +#include "debug.h" + +void handleMessage(const uint8_t *, size_t); +void handleMessageReceiverError(MessageReceiverError); + +extern "C" void SystemClock_Config(); + +Indicators indicators; + +const uint8_t ice40Bitstream[] = { +#include "bitstream.inc" +}; + +ICE40 ice40; + +SPICoaxTransceiver spiCoaxTransceiver; + +volatile uint16_t coaxBuffer[COAX_BUFFER_SIZE]; + +Coax coax(spiCoaxTransceiver, CoaxParity::Even, coaxBuffer, COAX_BUFFER_SIZE); + +volatile uint8_t messageBuffer[MESSAGE_BUFFER_SIZE]; + +MessageReceiver messageReceiver(messageBuffer, MESSAGE_BUFFER_SIZE, handleMessage, + handleMessageReceiverError); + +Interface interface(coax, indicators); + +int main(void) +{ + HAL_Init(); + + SystemClock_Config(); + + // Initialize the debug UART and GPIO devices. + Debug::init(); + + Debug::banner(); + + // Initialize the USB CDC device. + printf("\r\nInitializing USB CDC device..."); + + MX_USB_DEVICE_Init(); + + printf(" done.\r\n"); + + // Initialize the indicators. + MX_TIM6_Init(); + + indicators.init(); + + HAL_Delay(500); + + HAL_TIM_Base_Start_IT(&htim6); + + indicators.setStatus(INDICATORS_STATUS_CONFIGURING); + + // Configure the iCE40 FPGA. + printf("Configuring iCE40 FPGA..."); + + while (!ice40.configure(ice40Bitstream, sizeof(ice40Bitstream))) { + indicators.error(); + + HAL_Delay(1000); + } + + printf(" done.\r\n"); + + // Initialize the coax module. + printf("Initializing coax module..."); + + while (!coax.init()) { + indicators.error(); + + HAL_Delay(1000); + } + + printf(" done.\r\n"); + + HAL_Delay(500); + + indicators.setStatus(INDICATORS_STATUS_RUNNING); + + printf("\r\nREADY.\r\n"); + + while (true) { + messageReceiver.dispatch(); + } +} + +extern "C" void handleMessageData(const uint8_t *buffer, size_t bufferCount) +{ + messageReceiver.load(buffer, bufferCount); +} + +void handleMessage(const uint8_t *buffer, size_t bufferCount) +{ + interface.handleMessage(const_cast(buffer), bufferCount); +} + +void handleMessageReceiverError(MessageReceiverError error) +{ + interface.handleError(error); +} + +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim->Instance == htim6.Instance) { + indicators.update(); + } +} + +void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) +{ + if (GPIO_Pin == COAX_IRQ_Pin) { + coax.handleInterrupt(); + } +} + +void SystemClock_Config(void) +{ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); + + while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) { + } + + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + + LL_RCC_MSI_Enable(); + + while (LL_RCC_MSI_IsReady() != 1) { + } + + LL_RCC_MSI_EnableRangeSelection(); + LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6); + LL_RCC_MSI_SetCalibTrimming(0); + + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 40, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_EnableDomain_SYS(); + LL_RCC_PLL_Enable(); + + while (LL_RCC_PLL_IsReady() != 1) { + } + + LL_RCC_PLLSAI1_ConfigDomain_48M(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 24, LL_RCC_PLLSAI1Q_DIV_2); + LL_RCC_PLLSAI1_EnableDomain_48M(); + LL_RCC_PLLSAI1_Enable(); + + while (LL_RCC_PLLSAI1_IsReady() != 1) { + } + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { + } + + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + LL_SetSystemCoreClock(80000000); + + if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK) { + Error_Handler(); + } + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); +} + +void Error_Handler(void) +{ +} + +uint32_t bootMagic = 0x00000000; + +void resetToBootloader() +{ + bootMagic = 0x32703270; + + NVIC_SystemReset(); +} diff --git a/interface2/firmware/src/message.cpp b/interface2/firmware/src/message.cpp new file mode 100644 index 0000000..83c9c1a --- /dev/null +++ b/interface2/firmware/src/message.cpp @@ -0,0 +1,258 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "stm32l4xx_hal.h" + +#include "usbd_cdc_if.h" + +#include "debug.h" + +#include "message.h" + +#define MESSAGE_END 0xc0 +#define MESSAGE_ESCAPE 0xdb +#define MESSAGE_ESCAPE_END 0xdc +#define MESSAGE_ESCAPE_ESCAPE 0xdd + +MessageReceiver::MessageReceiver(volatile uint8_t *buffer, size_t bufferSize, + void (*messageCallback)(const uint8_t *, size_t), + void (*errorCallback)(MessageReceiverError)) : + _buffer(buffer), + _bufferSize(bufferSize), + _messageCallback(messageCallback), + _errorCallback(errorCallback) +{ + _timeout = 1000; + _lastReceiveTime = -1; + + _bufferCount = 0; + _state = MESSAGE_RECEIVER_STATE_WAIT_START; +} + +void MessageReceiver::load(const uint8_t *buffer, size_t bufferCount) +{ + _lastReceiveTime = HAL_GetTick(); + + for (size_t index = 0; index < bufferCount; index++) { + uint8_t byte = buffer[index]; + + if (_state == MESSAGE_RECEIVER_STATE_WAIT_START) { + if (byte == MESSAGE_END) { + _bufferCount = 0; + _state = MESSAGE_RECEIVER_STATE_DATA; + } + } else if (_state == MESSAGE_RECEIVER_STATE_DATA) { + if (byte == MESSAGE_END) { + if (_bufferCount > 0) { + _state = MESSAGE_RECEIVER_STATE_AVAILABLE; + } else { + _state = MESSAGE_RECEIVER_STATE_WAIT_START; + } + } else if (byte == MESSAGE_ESCAPE) { + _state = MESSAGE_RECEIVER_STATE_ESCAPE; + } else { + if (_bufferCount < _bufferSize) { + _buffer[_bufferCount++] = byte; + } else { + _state = MESSAGE_RECEIVER_STATE_DATA_OVERFLOW; + } + } + } else if (_state == MESSAGE_RECEIVER_STATE_ESCAPE) { + if (byte == MESSAGE_ESCAPE_END) { + if (_bufferCount < _bufferSize) { + _buffer[_bufferCount++] = MESSAGE_END; + _state = MESSAGE_RECEIVER_STATE_DATA; + } else { + _state = MESSAGE_RECEIVER_STATE_DATA_OVERFLOW; + } + } else if (byte == MESSAGE_ESCAPE_ESCAPE) { + if (_bufferCount < _bufferSize) { + _buffer[_bufferCount++] = MESSAGE_ESCAPE; + _state = MESSAGE_RECEIVER_STATE_DATA; + } else { + _state = MESSAGE_RECEIVER_STATE_DATA_OVERFLOW; + } + } else { + _state = MESSAGE_RECEIVER_STATE_WAIT_START; + } + } else if (_state == MESSAGE_RECEIVER_STATE_AVAILABLE) { + _state = MESSAGE_RECEIVER_STATE_MESSAGE_OVERFLOW; + } + } +} + +bool MessageReceiver::dispatch() +{ + if (_state == MESSAGE_RECEIVER_STATE_AVAILABLE || _state == MESSAGE_RECEIVER_STATE_MESSAGE_OVERFLOW) { + // In the case of a message overflow the message is still valid. + _messageCallback(const_cast(_buffer), _bufferCount); + + // A message overflow could occur during the above callback. + if (_state == MESSAGE_RECEIVER_STATE_MESSAGE_OVERFLOW) { + _errorCallback(MESSAGE_RECEIVER_ERROR_MESSAGE_OVERFLOW); + } + } else if (_state == MESSAGE_RECEIVER_STATE_DATA_OVERFLOW) { + _errorCallback(MESSAGE_RECEIVER_ERROR_DATA_OVERFLOW); + } else { + if (_state != MESSAGE_RECEIVER_STATE_WAIT_START) { + uint32_t lastReceiveTime = _lastReceiveTime; + uint32_t time = HAL_GetTick(); + + if (time - lastReceiveTime > _timeout) { + Debug::trap(201, "state = %d, lastReceiveTime = %d, time = %d", _state, lastReceiveTime, time); + + _state = MESSAGE_RECEIVER_STATE_WAIT_START; + + _errorCallback(MESSAGE_RECEIVER_ERROR_TIMEOUT); + } + } + + return false; + } + + _state = MESSAGE_RECEIVER_STATE_WAIT_START; + + return true; +} + +extern USBD_HandleTypeDef hUsbDeviceFS; + +HAL_StatusTypeDef transmit(const uint8_t *buffer, size_t bufferCount, uint32_t timeout) +{ + if (hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED) { + return HAL_ERROR; + } + + USBD_CDC_HandleTypeDef *cdc = reinterpret_cast(hUsbDeviceFS.pClassData); + + uint32_t startTime = HAL_GetTick(); + + while (cdc->TxState != 0) { + if (timeout != HAL_MAX_DELAY) { + if (HAL_GetTick() - startTime > timeout || timeout == 0) { + return HAL_TIMEOUT; + } + } + } + + HAL_StatusTypeDef status = (HAL_StatusTypeDef) CDC_Transmit_FS(const_cast(buffer), bufferCount); + + if (status != HAL_OK) { + return status; + } + + startTime = HAL_GetTick(); + + while (cdc->TxState != 0) { + if (timeout != HAL_MAX_DELAY) { + if (HAL_GetTick() - startTime > timeout || timeout == 0) { + return HAL_TIMEOUT; + } + } + } + + return HAL_OK; +} + +inline size_t encode(uint8_t *buffer, size_t size, uint8_t byte) +{ + if (byte == MESSAGE_END || byte == MESSAGE_ESCAPE) { + if (size < 2) { + return 0; + } + + buffer[0] = MESSAGE_ESCAPE; + + if (byte == MESSAGE_END) + buffer[1] = MESSAGE_ESCAPE_END; + else if (byte == MESSAGE_ESCAPE) + buffer[1] = MESSAGE_ESCAPE_ESCAPE; + + return 2; + } + + if (size < 1) { + return 0; + } + + buffer[0] = byte; + + return 1; +} + +#define PACKET_SIZE 64 + +// In order to simplify the breaking up of a message into multiple packets we reserve +// space at the end of every packet for the footer and end symbol. If the packet +// contained a real checksum in the footer then this would be at worst case 5 to +// allow for the encoding. +#define RESERVED 3 + +bool MessageSender::send(const uint8_t *buffer, size_t bufferCount) +{ + uint8_t packet[PACKET_SIZE]; + + size_t packetCount = 0; + size_t remainingPacketSize = PACKET_SIZE - RESERVED; + + // Start the message and encode the header, we assume that there is space for the header. + packet[packetCount++] = MESSAGE_END; + + remainingPacketSize--; + + size_t count = encode(&packet[packetCount], remainingPacketSize, (u_int8_t) (bufferCount >> 8)); + + packetCount += count; + remainingPacketSize -= count; + + count = encode(&packet[packetCount], remainingPacketSize, (u_int8_t) bufferCount); + + packetCount += count; + remainingPacketSize -= count; + + // Encode the data, once the packet size has been reached transmit the packet. + size_t index = 0; + + while (index < bufferCount) { + count = encode(&packet[packetCount], remainingPacketSize, buffer[index]); + + if (count > 0) { + index++; + } + + packetCount += count; + remainingPacketSize -= count; + + // Transmit the packet and begin a new packet. + if (count == 0 || remainingPacketSize == 0) { + if (transmit(packet, packetCount, 1000) != HAL_OK) { + return false; + } + + packetCount = 0; + remainingPacketSize = PACKET_SIZE - RESERVED; + } + } + + // Add the footer (space has been reserved), end the message and transmit the packet. + packet[packetCount++] = 0; + packet[packetCount++] = 0; + packet[packetCount++] = MESSAGE_END; + + if (!transmit(packet, packetCount, 1000)) { + return false; + } + + return true; +} diff --git a/interface2/fpga/Makefile b/interface2/fpga/Makefile new file mode 100644 index 0000000..55caf30 --- /dev/null +++ b/interface2/fpga/Makefile @@ -0,0 +1,13 @@ +SUBDIRS = tests rtl + +all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +clean: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean; \ + done + +.PHONY: all $(SUBDIRS) clean diff --git a/interface2/fpga/rtl/.gitignore b/interface2/fpga/rtl/.gitignore new file mode 100644 index 0000000..620a1b8 --- /dev/null +++ b/interface2/fpga/rtl/.gitignore @@ -0,0 +1,10 @@ +*.json +*.asc +*.bin + +# iCEcube2 +.mac_address +coax_Implmnt +synlog.tcl +*.log +*.log.bak diff --git a/interface2/fpga/rtl/Makefile b/interface2/fpga/rtl/Makefile new file mode 100644 index 0000000..1d9fa1f --- /dev/null +++ b/interface2/fpga/rtl/Makefile @@ -0,0 +1 @@ +include icecube2.mk diff --git a/interface2/fpga/rtl/clocks.sdc b/interface2/fpga/rtl/clocks.sdc new file mode 100644 index 0000000..06c654b --- /dev/null +++ b/interface2/fpga/rtl/clocks.sdc @@ -0,0 +1,2 @@ +create_clock -period 25.00 -name {clk} [get_ports {clk}] +create_clock -period 100.00 -name {spi_sck} [get_ports {spi_sck}] diff --git a/interface2/fpga/rtl/coax_buffer.v b/interface2/fpga/rtl/coax_buffer.v new file mode 100644 index 0000000..8feb4aa --- /dev/null +++ b/interface2/fpga/rtl/coax_buffer.v @@ -0,0 +1,94 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_buffer ( + input clk, + input reset, + input [9:0] write_data, + input write_strobe, + output [9:0] read_data, + input read_strobe, + output empty, + output full, + output reg almost_empty, + output reg almost_full +); + parameter DEPTH = 256; + parameter ALMOST_EMPTY_THRESHOLD = 64; + parameter ALMOST_FULL_THRESHOLD = 192; + + fifo_sync_ram #( + .DEPTH(DEPTH), + .WIDTH(10) + ) fifo ( + .wr_data(write_data), + .wr_ena(write_strobe), + .wr_full(full), + .rd_data(read_data), + .rd_ena(read_strobe), + .rd_empty(empty), + .clk(clk), + .rst(reset) + ); + + reg write_strobe_only; + reg read_strobe_only; + reg not_empty; + reg not_full; + + always @(posedge clk) + begin + write_strobe_only <= (write_strobe && !read_strobe); + read_strobe_only <= (read_strobe && !write_strobe); + + not_empty <= !empty; + not_full <= !full; + end + + reg increment_level; + reg decrement_level; + + always @(posedge clk) + begin + increment_level <= (write_strobe_only && not_full); + decrement_level <= (read_strobe_only && not_empty); + + if (reset) + begin + increment_level <= 0; + decrement_level <= 0; + end + end + + reg [$clog2(DEPTH):0] level; + + always @(posedge clk) + begin + if (increment_level) + level <= level + 1; + else if (decrement_level) + level <= level - 1; + + if (reset) + level <= 0; + end + + always @(posedge clk) + begin + almost_empty <= (level <= ALMOST_EMPTY_THRESHOLD); + almost_full <= (level >= ALMOST_FULL_THRESHOLD); + end +endmodule diff --git a/interface2/fpga/rtl/coax_buffered_rx.v b/interface2/fpga/rtl/coax_buffered_rx.v new file mode 100644 index 0000000..00caac5 --- /dev/null +++ b/interface2/fpga/rtl/coax_buffered_rx.v @@ -0,0 +1,85 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_buffered_rx ( + input clk, + input reset, + input rx, + output active, + output error, + output [9:0] data, + input read_strobe, + output empty, + output full, + input parity +); + parameter CLOCKS_PER_BIT = 8; + parameter DEPTH = 256; + + localparam ERROR_OVERFLOW = 10'b0000001000; + + wire coax_rx_error; + wire [9:0] coax_rx_data; + wire coax_rx_strobe; + + coax_rx #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) coax_rx ( + .clk(clk), + .reset(reset), + .rx(rx), + .active(active), + .error(coax_rx_error), + .data(coax_rx_data), + .strobe(coax_rx_strobe), + .parity(parity) + ); + + wire [9:0] coax_buffer_data; + + coax_buffer #( + .DEPTH(DEPTH) + ) coax_buffer ( + .clk(clk), + .reset(reset), + .write_data(coax_rx_data), + .write_strobe(coax_rx_strobe), + .read_data(coax_buffer_data), + .read_strobe(read_strobe && !error), + .empty(empty), + .full(full) + ); + + wire overflow; + + assign overflow = ((active && !previous_active && !empty) || (coax_rx_strobe && full)); + + reg overflowed = 0; + reg previous_active; + + always @(posedge clk) + begin + if (reset) + overflowed <= 0; + else if (overflow) + overflowed <= 1; + + previous_active <= active; + end + + assign error = overflow || overflowed || coax_rx_error; + assign data = (overflow || overflowed) ? ERROR_OVERFLOW : (coax_rx_error ? coax_rx_data : (empty ? 10'b0 : coax_buffer_data)); +endmodule diff --git a/interface2/fpga/rtl/coax_buffered_tx.v b/interface2/fpga/rtl/coax_buffered_tx.v new file mode 100644 index 0000000..aa6ad1f --- /dev/null +++ b/interface2/fpga/rtl/coax_buffered_tx.v @@ -0,0 +1,151 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_buffered_tx ( + input clk, + input reset, + output active, + output tx, + input [9:0] data, + input load_strobe, + input start_strobe, + output empty, + output full, + output reg ready, + input parity +); + parameter CLOCKS_PER_BIT = 8; + parameter DEPTH = 256; + parameter START_DEPTH = DEPTH * 0.75; + + localparam STATE_IDLE = 0; + localparam STATE_TRANSMITTING_1 = 1; + localparam STATE_TRANSMITTING_2 = 2; + localparam STATE_TRANSMITTING_3 = 3; + + reg [1:0] state = STATE_IDLE; + reg [1:0] next_state; + + reg next_ready; + + wire [9:0] coax_tx_data; + reg coax_tx_strobe = 0; + reg next_coax_tx_strobe; + wire coax_tx_ready; + + coax_tx #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) coax_tx ( + .clk(clk), + .reset(reset), + .active(active), + .tx(tx), + .data(coax_tx_data), + .strobe(coax_tx_strobe), + .ready(coax_tx_ready), + .parity(parity) + ); + + reg coax_buffer_read_strobe = 0; + reg next_coax_buffer_read_strobe; + wire coax_buffer_almost_full; + + coax_buffer #( + .DEPTH(DEPTH), + .ALMOST_FULL_THRESHOLD(START_DEPTH) + ) coax_buffer ( + .clk(clk), + .reset(reset), + .write_data(data), + .write_strobe(load_strobe), + .read_data(coax_tx_data), + .read_strobe(coax_buffer_read_strobe), + .empty(empty), + .almost_full(coax_buffer_almost_full), + .full(full) + ); + + always @(*) + begin + next_state = state; + + next_coax_tx_strobe = 0; + next_coax_buffer_read_strobe = 0; + + next_ready = 1; + + case (state) + STATE_IDLE: + begin + // NOTE: Redundant check of almost full AND not empty is in + // order to protect against bugs with the almost full logic. + if ((start_strobe || coax_buffer_almost_full) && !empty) + next_state = STATE_TRANSMITTING_1; + end + + STATE_TRANSMITTING_1: + begin + if (coax_tx_ready) + begin + if (!empty) + begin + next_coax_tx_strobe = 1; + next_state = STATE_TRANSMITTING_2; + end + else + begin + next_ready = 0; + next_state = STATE_TRANSMITTING_3; + end + end + end + + STATE_TRANSMITTING_2: + begin + next_coax_buffer_read_strobe = 1; + next_state = STATE_TRANSMITTING_1; + end + + STATE_TRANSMITTING_3: + begin + next_ready = 0; + + if (!active) + next_state = STATE_IDLE; + end + endcase + end + + always @(posedge clk) + begin + state <= next_state; + + coax_tx_strobe <= next_coax_tx_strobe; + coax_buffer_read_strobe <= next_coax_buffer_read_strobe; + + ready <= next_ready; + + if (reset) + begin + state <= STATE_IDLE; + + coax_tx_strobe <= 0; + coax_buffer_read_strobe <= 0; + + ready <= 1; + end + end +endmodule diff --git a/interface2/fpga/rtl/coax_rx.v b/interface2/fpga/rtl/coax_rx.v new file mode 100644 index 0000000..1071a73 --- /dev/null +++ b/interface2/fpga/rtl/coax_rx.v @@ -0,0 +1,415 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_rx ( + input clk, + input reset, + input rx, + output reg active, + output reg error, + output reg [9:0] data, + output reg strobe = 0, + input parity +); + parameter CLOCKS_PER_BIT = 8; + + localparam ERROR_LOSS_OF_MID_BIT_TRANSITION = 10'b0000000001; + localparam ERROR_PARITY = 10'b0000000010; + localparam ERROR_INVALID_END_SEQUENCE = 10'b0000000100; + + localparam STATE_IDLE = 0; + localparam STATE_START_SEQUENCE_1 = 1; + localparam STATE_START_SEQUENCE_2 = 2; + localparam STATE_START_SEQUENCE_3 = 3; + localparam STATE_START_SEQUENCE_4 = 4; + localparam STATE_START_SEQUENCE_5 = 5; + localparam STATE_START_SEQUENCE_6 = 6; + localparam STATE_START_SEQUENCE_7 = 7; + localparam STATE_START_SEQUENCE_8 = 8; + localparam STATE_START_SEQUENCE_9 = 9; + localparam STATE_SYNC_BIT = 10; + localparam STATE_DATA_BIT = 11; + localparam STATE_PARITY_BIT = 12; + localparam STATE_END_SEQUENCE_1 = 13; + localparam STATE_END_SEQUENCE_2 = 14; + localparam STATE_ERROR = 15; + + reg [3:0] state = STATE_IDLE; + reg [3:0] next_state; + reg [7:0] state_counter; + reg [7:0] next_state_counter; + + reg previous_rx; + + reg bit_timer_reset = 0; + reg next_bit_timer_reset; + + reg [9:0] next_data; + reg next_strobe; + + reg [9:0] input_data; + reg [9:0] next_input_data; + reg input_data_parity; + + reg [3:0] bit_counter = 0; + reg [3:0] next_bit_counter; + + reg next_active; + reg next_error; + + wire sample; + wire synchronized; + + coax_rx_bit_timer #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) bit_timer ( + .clk(clk), + .rx(rx), + .reset(bit_timer_reset), + .sample(sample), + .synchronized(synchronized) + ); + + always @(*) + begin + next_state = state; + next_state_counter = state_counter + 1; + + next_bit_timer_reset = 0; + + next_data = data; + next_strobe = 0; + + next_input_data = input_data; + next_bit_counter = bit_counter; + + next_active = 0; + next_error = 0; + + case (state) + STATE_IDLE: + begin + next_bit_timer_reset = 1; + + if (!rx && previous_rx) + begin + next_state = STATE_START_SEQUENCE_1; + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_1: + begin + if (sample) + begin + if (synchronized && rx) + next_state = STATE_START_SEQUENCE_2; + else + next_state = STATE_IDLE; + + next_state_counter = 0; + end + else if (state_counter >= (CLOCKS_PER_BIT * 2)) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_2: + begin + if (sample) + begin + if (synchronized && rx) + next_state = STATE_START_SEQUENCE_3; + else + next_state = STATE_IDLE; + + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_3: + begin + if (sample) + begin + if (synchronized && rx) + next_state = STATE_START_SEQUENCE_4; + else + next_state = STATE_IDLE; + + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_4: + begin + if (sample) + begin + if (synchronized && rx) + next_state = STATE_START_SEQUENCE_5; + else + next_state = STATE_IDLE; + + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_5: + begin + if (sample) + begin + if (synchronized && rx) + next_state = STATE_START_SEQUENCE_6; + else + next_state = STATE_IDLE; + + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_6: + begin + if (!rx) + begin + next_state = STATE_START_SEQUENCE_7; + next_state_counter = 0; + end + else if (state_counter >= CLOCKS_PER_BIT) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_7: + begin + if (rx) + begin + next_state = STATE_START_SEQUENCE_8; + next_state_counter = 0; + end + else if (state_counter >= (CLOCKS_PER_BIT * 2)) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_8: + begin + if (!rx) + begin + next_bit_timer_reset = 1; + next_state = STATE_START_SEQUENCE_9; + next_state_counter = 0; + end + else if (state_counter >= (CLOCKS_PER_BIT * 2)) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_START_SEQUENCE_9: + begin + // This is really the first STATE_SYNC_BIT but we treat it + // differently and consider it part of the start + // sequence. + + if (sample && synchronized) + begin + if (rx) + begin + next_bit_counter = 0; + next_state = STATE_DATA_BIT; + end + else + begin + next_state = STATE_IDLE; + end + + next_state_counter = 0; + end + else if (state_counter >= CLOCKS_PER_BIT) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_SYNC_BIT: + begin + next_active = 1; + + if (sample) + begin + if (synchronized) + begin + if (rx) + begin + next_bit_counter = 0; + next_state = STATE_DATA_BIT; + end + else + begin + next_state = STATE_END_SEQUENCE_1; + end + + next_state_counter = 0; + end + else + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; + next_state_counter = 0; + end + end + end + + STATE_DATA_BIT: + begin + next_active = 1; + + if (sample) + begin + if (synchronized) + begin + next_input_data = { input_data[8:0], rx }; + + if (bit_counter < 9) + begin + next_bit_counter = bit_counter + 1; + end + else + begin + next_state = STATE_PARITY_BIT; + end + + next_state_counter = 0; + end + else + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; + next_state_counter = 0; + end + end + end + + STATE_PARITY_BIT: + begin + next_active = 1; + + if (sample) + begin + if (synchronized) + begin + if (rx == input_data_parity) + begin + next_strobe = 1; + next_data = input_data; + next_state = STATE_SYNC_BIT; + end + else + begin + next_data = ERROR_PARITY; + next_state = STATE_ERROR; + end + + next_state_counter = 0; + end + else + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; + next_state_counter = 0; + end + end + end + + STATE_END_SEQUENCE_1: + begin + if (rx) + begin + next_state = STATE_END_SEQUENCE_2; + next_state_counter = 0; + end + else if (state_counter >= CLOCKS_PER_BIT) + begin + next_data = ERROR_INVALID_END_SEQUENCE; + next_state = STATE_ERROR; + next_state_counter = 0; + end + end + + STATE_END_SEQUENCE_2: + begin + // TODO: should this go to ERROR on timeout? + if (!rx) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + else if (state_counter >= (CLOCKS_PER_BIT * 2)) + begin + next_state = STATE_IDLE; + next_state_counter = 0; + end + end + + STATE_ERROR: + begin + next_error = 1; + end + endcase + end + + always @(posedge clk) + begin + state <= next_state; + state_counter <= next_state_counter; + + bit_timer_reset <= next_bit_timer_reset; + + data <= next_data; + strobe <= next_strobe; + + input_data <= next_input_data; + + // Parity includes the sync bit. + input_data_parity <= (parity == 1 ? ^{ 1'b1, input_data } : ~^{ 1'b1, input_data }); + + bit_counter <= next_bit_counter; + + active <= next_active; + error <= next_error; + + if (reset) + begin + bit_timer_reset <= 1; + + state <= STATE_IDLE; + + strobe <= 0; + + active <= 0; + error <= 0; + end + + previous_rx <= rx; + end +endmodule diff --git a/interface2/fpga/rtl/coax_rx_bit_timer.v b/interface2/fpga/rtl/coax_rx_bit_timer.v new file mode 100644 index 0000000..2f83e7e --- /dev/null +++ b/interface2/fpga/rtl/coax_rx_bit_timer.v @@ -0,0 +1,111 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_rx_bit_timer ( + input clk, + input rx, + input reset, + output reg sample, + output reg synchronized +); + parameter CLOCKS_PER_BIT = 8; + + localparam IDLE = 0; + localparam SYNCHRONIZED = 1; + localparam UNSYNCHRONIZED = 2; + + reg [1:0] state = IDLE; + reg [1:0] next_state; + + reg previous_rx; + + reg [$clog2(CLOCKS_PER_BIT*2):0] transition_counter = 0; + reg [$clog2(CLOCKS_PER_BIT*2):0] next_transition_counter; + reg [$clog2(CLOCKS_PER_BIT):0] bit_counter = 0; + reg [$clog2(CLOCKS_PER_BIT):0] next_bit_counter; + + always @(*) + begin + next_state = state; + + sample = 0; + synchronized = 0; + + next_transition_counter = transition_counter; + next_bit_counter = bit_counter; + + case (state) + IDLE: + begin + if (rx != previous_rx) + begin + next_transition_counter = 0; + next_bit_counter = CLOCKS_PER_BIT / 2; + + next_state = SYNCHRONIZED; + end + end + + SYNCHRONIZED: + begin + if (transition_counter < (CLOCKS_PER_BIT + (CLOCKS_PER_BIT / 4))) + next_transition_counter = transition_counter + 1; + else + next_state = UNSYNCHRONIZED; + + synchronized = 1; + + if (bit_counter < CLOCKS_PER_BIT) + next_bit_counter = bit_counter + 1; + else + next_bit_counter = 0; + + if (rx != previous_rx && transition_counter > (CLOCKS_PER_BIT / 2)) + begin + next_transition_counter = 0; + next_bit_counter = CLOCKS_PER_BIT / 2; + end + + if (bit_counter == ((CLOCKS_PER_BIT / 4) * 3)) + sample = 1; + end + + UNSYNCHRONIZED: + begin + if (bit_counter < CLOCKS_PER_BIT) + next_bit_counter = bit_counter + 1; + else + next_bit_counter = 0; + + if (bit_counter == ((CLOCKS_PER_BIT / 4) * 3)) + sample = 1; + end + endcase + end + + always @(posedge clk) + begin + state <= next_state; + + transition_counter <= next_transition_counter; + bit_counter <= next_bit_counter; + + if (reset) + state <= IDLE; + + previous_rx <= rx; + end +endmodule diff --git a/interface2/fpga/rtl/coax_syn.prj b/interface2/fpga/rtl/coax_syn.prj new file mode 100644 index 0000000..38f3c7c --- /dev/null +++ b/interface2/fpga/rtl/coax_syn.prj @@ -0,0 +1,71 @@ +#-- Synopsys, Inc. +#-- Project file /home/andrew/lattice_coax/coax/coax_syn.prj +#project files + +add_file -verilog -lib work "coax_buffered_rx.v" +add_file -verilog -lib work "coax_rx.v" +add_file -verilog -lib work "coax_rx_bit_timer.v" +add_file -verilog -lib work "coax_tx.v" +add_file -verilog -lib work "coax_tx_bit_timer.v" +add_file -verilog -lib work "coax_tx_distorter.v" +add_file -verilog -lib work "control.v" +add_file -verilog -lib work "spi_device.v" +add_file -verilog -lib work "coax_buffered_tx.v" +add_file -verilog -lib work "coax_buffer.v" +add_file -verilog -lib work "third_party/fifo_sync_ram.v" +add_file -verilog -lib work "third_party/ram_sdp.v" +add_file -verilog -lib work "strobe_cdc.v" +add_file -verilog -lib work "top.v" +add_file -verilog -lib work "dual_clock_spi_device.v" +add_file -constraint -lib work "clocks.sdc" +#implementation: "coax_Implmnt" +impl -add coax_Implmnt -type fpga + +#implementation attributes +set_option -vlog_std v2001 +set_option -project_relative_includes 1 + +#device options +set_option -technology SBTiCE40UP +set_option -part iCE40UP5K +set_option -package SG48 +set_option -speed_grade +set_option -part_companion "" + +#compilation/mapping options + +# mapper_options +set_option -frequency auto +set_option -write_verilog 0 +set_option -write_vhdl 0 + +# Silicon Blue iCE40UP +set_option -maxfan 10000 +set_option -disable_io_insertion 0 +set_option -pipe 1 +set_option -retiming 0 +set_option -update_models_cp 0 +set_option -fixgatedclocks 2 +set_option -fixgeneratedclocks 0 + +# NFilter +set_option -popfeed 0 +set_option -constprop 0 +set_option -createhierarchy 0 + +# sequential_optimization_options +set_option -symbolic_fsm_compiler 1 + +# Compiler Options +set_option -compiler_compatible 0 +set_option -resource_sharing 1 + +#automatic place and route (vendor) options +set_option -write_apr_constraint 1 + +#set result format/file last +project -result_format "edif" +project -result_file ./coax_Implmnt/coax.edf +project -log_file "./coax_Implmnt/coax.srr" +impl -active coax_Implmnt +project -run synthesis -clean diff --git a/interface2/fpga/rtl/coax_tx.v b/interface2/fpga/rtl/coax_tx.v new file mode 100644 index 0000000..838a6b1 --- /dev/null +++ b/interface2/fpga/rtl/coax_tx.v @@ -0,0 +1,308 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_tx ( + input clk, + input reset, + output reg active, + output reg tx, + input [9:0] data, + input strobe, + output ready, + input parity +); + parameter CLOCKS_PER_BIT = 8; + + localparam IDLE = 0; + localparam START_SEQUENCE_1 = 1; + localparam START_SEQUENCE_2 = 2; + localparam START_SEQUENCE_3 = 3; + localparam START_SEQUENCE_4 = 4; + localparam START_SEQUENCE_5 = 5; + localparam START_SEQUENCE_6 = 6; + localparam START_SEQUENCE_7 = 7; + localparam START_SEQUENCE_8 = 8; + localparam START_SEQUENCE_9 = 9; + localparam SYNC_BIT = 10; + localparam DATA_BIT = 11; + localparam PARITY_BIT = 12; + localparam END_SEQUENCE_1 = 13; + localparam END_SEQUENCE_2 = 14; + localparam END_SEQUENCE_3 = 15; + + reg [3:0] state = IDLE; + reg [3:0] next_state; + + reg next_tx; + + reg end_sequence; + reg next_end_sequence; + + reg [9:0] output_data; + reg [9:0] next_output_data; + reg output_data_full = 0; + reg next_output_data_full; + reg parity_bit; + reg next_parity_bit; + reg output_parity_bit; + reg next_output_parity_bit; + + reg [3:0] bit_counter = 0; + reg [3:0] next_bit_counter; + + reg bit_timer_reset = 0; + reg next_bit_timer_reset; + + wire first_half; + wire second_half; + wire last_clock; + + coax_tx_bit_timer #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) bit_timer ( + .clk(clk), + .reset(bit_timer_reset), + .first_half(first_half), + .second_half(second_half), + .last_clock(last_clock) + ); + + always @(*) + begin + next_state = state; + + next_tx = 0; + + next_end_sequence = 0; + + next_output_data = output_data; + next_output_data_full = output_data_full; + next_parity_bit = parity_bit; + next_output_parity_bit = output_parity_bit; + + if (strobe && ready) + begin + next_output_data = data; + next_output_data_full = 1; + + // Parity includes the sync bit. + next_parity_bit = (parity == 1 ? ^{ 1'b1, data } : ~^{ 1'b1, data }); + end + + next_bit_counter = bit_counter; + + next_bit_timer_reset = 0; + + case (state) + IDLE: + begin + next_bit_timer_reset = 1; + + if (output_data_full) + begin + next_state = START_SEQUENCE_1; + end + end + + START_SEQUENCE_1: + begin + next_tx = 1; + + // TODO... off by 1 + if (second_half) + begin + next_bit_timer_reset = 1; + next_state = START_SEQUENCE_2; + end + end + + START_SEQUENCE_2: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_3; + end + + START_SEQUENCE_3: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_4; + end + + START_SEQUENCE_4: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_5; + end + + START_SEQUENCE_5: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_6; + end + + START_SEQUENCE_6: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_7; + end + + START_SEQUENCE_7: + begin + next_tx = 0; + + if (last_clock) + next_state = START_SEQUENCE_8; + end + + START_SEQUENCE_8: + begin + next_tx = first_half ? 0 : 1; + + if (last_clock) + next_state = START_SEQUENCE_9; + end + + START_SEQUENCE_9: + begin + next_tx = 1; + + if (last_clock) + next_state = SYNC_BIT; + end + + SYNC_BIT: + begin + next_tx = first_half ? 0 : 1; + + next_bit_counter = 9; + + if (last_clock) + next_state = DATA_BIT; + end + + DATA_BIT: + begin + next_tx = first_half ? ~output_data[9] : output_data[9]; + + if (last_clock) + begin + next_output_data = { output_data[8:0], output_data[9] }; + next_bit_counter = bit_counter - 1; + + if (bit_counter == 0) + begin + next_output_data_full = 0; + next_output_parity_bit = parity_bit; + + next_state = PARITY_BIT; + end + end + end + + PARITY_BIT: + begin + next_tx = first_half ? ~output_parity_bit : output_parity_bit; + + if (last_clock) + begin + if (output_data_full) + begin + next_state = SYNC_BIT; + end + else + begin + next_end_sequence = 1; + next_state = END_SEQUENCE_1; + end + end + end + + END_SEQUENCE_1: + begin + next_tx = first_half ? 1 : 0; + next_end_sequence = 1; + + if (last_clock) + next_state = END_SEQUENCE_2; + end + + END_SEQUENCE_2: + begin + next_tx = 1; + next_end_sequence = 1; + + if (last_clock) + next_state = END_SEQUENCE_3; + end + + END_SEQUENCE_3: + begin + next_tx = 1; + next_end_sequence = 1; + + if (last_clock) + begin + next_tx = 0; + next_end_sequence = 0; + next_state = IDLE; + end + end + endcase + end + + always @(posedge clk) + begin + state <= next_state; + + active <= (state != IDLE); // TODO: this causes active to remain high one additional clock cycle + tx <= next_tx; + + end_sequence <= next_end_sequence; + + output_data <= next_output_data; + output_data_full <= next_output_data_full; + parity_bit <= next_parity_bit; + output_parity_bit <= next_output_parity_bit; + + bit_counter <= next_bit_counter; + + bit_timer_reset <= next_bit_timer_reset; + + if (reset) + begin + state <= IDLE; + + active <= 0; + tx <= 0; + + end_sequence <= 0; + + output_data_full <= 0; + end + end + + assign ready = (!output_data_full && !end_sequence); +endmodule diff --git a/interface2/fpga/rtl/coax_tx_bit_timer.v b/interface2/fpga/rtl/coax_tx_bit_timer.v new file mode 100644 index 0000000..21fcc18 --- /dev/null +++ b/interface2/fpga/rtl/coax_tx_bit_timer.v @@ -0,0 +1,46 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_tx_bit_timer ( + input clk, + input reset, + output first_half, + output second_half, + output last_clock +); + parameter CLOCKS_PER_BIT = 8; + + reg [$clog2(CLOCKS_PER_BIT):0] counter = 0; + reg [$clog2(CLOCKS_PER_BIT):0] next_counter; + + always @(*) + begin + next_counter = last_clock ? 0 : counter + 1; + end + + always @(posedge clk) + begin + counter <= next_counter; + + if (reset) + counter <= 0; + end + + assign first_half = (counter < CLOCKS_PER_BIT / 2); + assign second_half = ~first_half; + + assign last_clock = (counter == CLOCKS_PER_BIT - 1); +endmodule diff --git a/interface2/fpga/rtl/coax_tx_distorter.v b/interface2/fpga/rtl/coax_tx_distorter.v new file mode 100644 index 0000000..c64804c --- /dev/null +++ b/interface2/fpga/rtl/coax_tx_distorter.v @@ -0,0 +1,53 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_tx_distorter ( + input clk, + input active_input, + input tx_input, + output reg active_output, + output reg tx_output, + output reg tx_delay, + output reg tx_n +); + parameter CLOCKS_PER_BIT = 8; + + localparam DELAY_CLOCKS = CLOCKS_PER_BIT / 4; + + reg [DELAY_CLOCKS-1:0] tx_d = { (DELAY_CLOCKS){1'b1} }; + + always @(posedge clk) + begin + if (active_input) + begin + tx_d <= { tx_d[DELAY_CLOCKS-2:0], tx_input }; + + active_output <= 1; + tx_output <= tx_input; + tx_delay <= tx_d[DELAY_CLOCKS-1]; + tx_n <= ~tx_input; + end + else + begin + tx_d <= { (DELAY_CLOCKS){1'b1} }; + + active_output <= 0; + tx_output <= 0; + tx_delay <= 0; + tx_n <= 0; + end + end +endmodule diff --git a/interface2/fpga/rtl/control.v b/interface2/fpga/rtl/control.v new file mode 100644 index 0000000..b397eea --- /dev/null +++ b/interface2/fpga/rtl/control.v @@ -0,0 +1,347 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module control ( + input clk, + input reset, + + // SPI + input spi_cs_n, + input [7:0] spi_rx_data, + input spi_rx_strobe, + output reg [7:0] spi_tx_data, + output reg spi_tx_strobe, + + output loopback, + + // TX + output reg tx_reset, + input tx_active, + output reg [9:0] tx_data, + output reg tx_load_strobe, + output reg tx_start_strobe, + input tx_empty, + input tx_full, + input tx_ready, + output tx_parity, + + // RX + output reg rx_reset, + input rx_active, + input rx_error, + input [9:0] rx_data, + output reg rx_read_strobe, + input rx_empty, + output rx_parity +); + parameter DEFAULT_CONTROL_REGISTER = 8'b01001000; + + localparam STATE_IDLE = 0; + localparam STATE_READ_REGISTER_1 = 1; + localparam STATE_READ_REGISTER_2 = 2; + localparam STATE_WRITE_REGISTER_1 = 3; + localparam STATE_WRITE_REGISTER_2 = 4; + localparam STATE_TX_1 = 5; + localparam STATE_TX_2 = 6; + localparam STATE_TX_3 = 7; + localparam STATE_RX_1 = 8; + localparam STATE_RX_2 = 9; + localparam STATE_RX_3 = 10; + localparam STATE_RX_4 = 11; + localparam STATE_RESET = 12; + + reg [7:0] state = STATE_IDLE; + reg [7:0] next_state; + + reg [7:0] control_register = DEFAULT_CONTROL_REGISTER; + reg [7:0] next_control_register; + reg [7:0] register_mask; + reg [7:0] next_register_mask; + + reg [7:0] command; + reg [7:0] next_command; + + reg [7:0] next_spi_tx_data; + reg next_spi_tx_strobe; + + reg next_tx_reset; + reg previous_tx_active; + reg [9:0] next_tx_data; + reg tx_data_valid = 0; + reg next_tx_data_valid; + reg next_tx_load_strobe; + reg next_tx_start_strobe; + reg tx_complete = 0; + reg next_tx_complete; + + reg next_rx_reset; + reg next_rx_read_strobe; + reg [15:0] rx_buffer; + reg [15:0] next_rx_buffer; + + reg [1:0] spi_cs_n_d; + + always @(posedge clk) + begin + spi_cs_n_d <= { spi_cs_n_d[0], spi_cs_n }; + end + + always @(*) + begin + next_state = state; + + next_control_register = control_register; + next_register_mask = register_mask; + + next_command = command; + + next_spi_tx_data = spi_tx_data; + next_spi_tx_strobe = 0; + + next_tx_reset = 0; + next_tx_data = tx_data; + next_tx_data_valid = tx_data_valid; + next_tx_load_strobe = 0; + next_tx_start_strobe = 0; + next_tx_complete = tx_complete; + + next_rx_reset = 0; + next_rx_read_strobe = 0; + next_rx_buffer = rx_buffer; + + case (state) + STATE_IDLE: + begin + if (spi_rx_strobe) + begin + next_command = spi_rx_data; + + case (spi_rx_data[3:0]) + 4'h2: next_state = STATE_READ_REGISTER_1; + 4'h3: next_state = STATE_WRITE_REGISTER_1; + 4'h4: next_state = STATE_TX_1; + 4'h5: next_state = STATE_RX_1; + 4'hf: next_state = STATE_RESET; + endcase + end + end + + STATE_READ_REGISTER_1: + begin + next_spi_tx_data = 0; + + case (command[7:4]) + 4'h1: next_spi_tx_data = { 1'b0, rx_error, rx_active, 1'b0, tx_complete, tx_active, 2'b0 }; + 4'h2: next_spi_tx_data = control_register; + 4'hf: next_spi_tx_data = 8'ha5; + endcase + + next_spi_tx_strobe = 1; + + next_state = STATE_READ_REGISTER_2; + end + + STATE_READ_REGISTER_2: + begin + if (spi_rx_strobe) + next_state = STATE_READ_REGISTER_1; + end + + STATE_WRITE_REGISTER_1: + begin + if (spi_rx_strobe) + begin + next_register_mask = spi_rx_data; + + next_state = STATE_WRITE_REGISTER_2; + end + end + + STATE_WRITE_REGISTER_2: + begin + if (spi_rx_strobe) + begin + case (command[7:4]) + 4'h2: next_control_register = (control_register & ~register_mask) | (spi_rx_data & register_mask); + endcase + + next_state = STATE_IDLE; + end + end + + STATE_TX_1: + begin + next_tx_complete = 0; + next_state = STATE_TX_2; + end + + STATE_TX_2: + begin + if (spi_rx_strobe) + begin + next_tx_data_valid = 0; + + if (tx_full) + begin + next_spi_tx_data = 8'b10000001; // Overflow + next_spi_tx_strobe = 1; + end + else if (!tx_ready) + begin + next_spi_tx_data = 8'b10000010; // Underflow + next_spi_tx_strobe = 1; + end + else + begin + next_tx_data = { spi_rx_data[1:0], 8'b00000000 }; + next_tx_data_valid = 1; + + next_spi_tx_data = 8'h00; + next_spi_tx_strobe = 1; + end + + next_state = STATE_TX_3; + end + end + + STATE_TX_3: + begin + if (spi_rx_strobe) + begin + next_tx_data = { tx_data[9:8], spi_rx_data }; + next_tx_load_strobe = tx_data_valid; + + next_state = STATE_TX_2; + end + end + + STATE_RX_1: + begin + next_rx_buffer = { rx_error, rx_empty, 4'b0000, rx_data }; + + next_state = STATE_RX_2; + end + + STATE_RX_2: + begin + next_spi_tx_data = rx_buffer[15:8]; + next_spi_tx_strobe = 1; + + next_state = STATE_RX_3; + end + + STATE_RX_3: + begin + if (spi_rx_strobe) + begin + next_spi_tx_data = rx_buffer[7:0]; + next_spi_tx_strobe = 1; + + // Reset on error and only dequeue if not empty. + if (rx_buffer[15]) + next_rx_reset = 1; // TODO: should this be more explicit? + else if (!rx_buffer[14]) + next_rx_read_strobe = 1; + + next_state = STATE_RX_4; + end + end + + STATE_RX_4: + begin + if (spi_rx_strobe) + next_state = STATE_RX_1; + end + + STATE_RESET: + begin + // TODO: should this also reset the control register flags + // like loopback? + + next_tx_reset = 1; + next_tx_complete = 0; + + next_rx_reset = 1; + + next_state = STATE_IDLE; + end + endcase + + if (spi_cs_n_d[1]) + begin + if (!tx_empty && !tx_active) + next_tx_start_strobe = 1; // TODO: this can last for multiple clock cycles, but that is okay... + + next_state = STATE_IDLE; + end + + if (!tx_active && previous_tx_active) + next_tx_complete = 1; + end + + always @(posedge clk) + begin + state <= next_state; + + control_register <= next_control_register; + register_mask <= next_register_mask; + + command <= next_command; + + spi_tx_data <= next_spi_tx_data; + spi_tx_strobe <= next_spi_tx_strobe; + + tx_reset <= next_tx_reset; + tx_data <= next_tx_data; + tx_data_valid <= next_tx_data_valid; + tx_load_strobe <= next_tx_load_strobe; + tx_start_strobe <= next_tx_start_strobe; + tx_complete <= next_tx_complete; + + rx_reset <= next_rx_reset; + rx_read_strobe <= next_rx_read_strobe; + rx_buffer <= next_rx_buffer; + + if (reset) + begin + state <= STATE_IDLE; + + control_register <= DEFAULT_CONTROL_REGISTER; + + command <= 0; + + spi_tx_data <= 0; + spi_tx_strobe <= 0; + + tx_reset <= 0; + tx_data <= 0; + tx_load_strobe <= 0; + tx_start_strobe <= 0; + tx_complete <= 0; + + rx_reset <= 0; + rx_read_strobe <= 0; + rx_buffer <= 0; + end + + previous_tx_active <= tx_active; + end + + assign loopback = control_register[0]; + + assign tx_parity = control_register[3]; + assign rx_parity = control_register[6]; +endmodule diff --git a/interface2/fpga/rtl/dual_clock_spi_device.v b/interface2/fpga/rtl/dual_clock_spi_device.v new file mode 100644 index 0000000..d0afe7b --- /dev/null +++ b/interface2/fpga/rtl/dual_clock_spi_device.v @@ -0,0 +1,75 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module dual_clock_spi_device ( + input clk_slow, + input clk_fast, + input spi_sck, + input spi_cs_n, + input spi_sdi, + output spi_sdo, + output reg [7:0] rx_data, + output reg rx_strobe, + input [7:0] tx_data, + input tx_strobe +); + wire [7:0] rx_data_fast; + wire rx_strobe_fast; + reg [7:0] tx_data_fast; + wire tx_strobe_fast; + + spi_device spi ( + .clk(clk_fast), + .spi_sck(spi_sck), + .spi_cs_n(spi_cs_n), + .spi_sdi(spi_sdi), + .spi_sdo(spi_sdo), + .rx_data(rx_data_fast), + .rx_strobe(rx_strobe_fast), + .tx_data(tx_data_fast), + .tx_strobe(tx_strobe_fast) + ); + + wire rx_strobe_slow; + + strobe_cdc rx_strobe_cdc ( + .clk_in(clk_fast), + .strobe_in(rx_strobe_fast), + .clk_out(clk_slow), + .strobe_out(rx_strobe_slow) + ); + + strobe_cdc tx_strobe_cdc ( + .clk_in(clk_slow), + .strobe_in(tx_strobe), + .clk_out(clk_fast), + .strobe_out(tx_strobe_fast) + ); + + always @(posedge clk_slow) + begin + if (tx_strobe) + tx_data_fast <= tx_data; + + rx_strobe <= 0; + + if (rx_strobe_slow) + begin + rx_data <= rx_data_fast; + rx_strobe <= 1; + end + end +endmodule diff --git a/interface2/fpga/rtl/icecube2.mk b/interface2/fpga/rtl/icecube2.mk new file mode 100644 index 0000000..5698292 --- /dev/null +++ b/interface2/fpga/rtl/icecube2.mk @@ -0,0 +1,20 @@ +# See https://github.com/halfmanhalftaco/fpga-docker/tree/master/Lattice_iCEcube2 +ICECUBE2_WRAPPER = docker run -it --rm --volume $(RTL):/data --workdir /data --mac-address=$(shell cat .mac_address) icecube2:latest ./icecube2_env.sh + +RTL = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) +IMPLMNT = coax_Implmnt + +all: top.bin + +$(IMPLMNT)/coax.edf: coax_syn.prj *.v third_party/*.v clocks.sdc + $(ICECUBE2_WRAPPER) synpwrap -prj coax_syn.prj + +top.bin: $(IMPLMNT)/coax.edf pins.pcf + rm -f top.bin + $(ICECUBE2_WRAPPER) ./icecube2_flow.tcl + cp $(IMPLMNT)/sbt/outputs/bitmap/top_bitmap.bin top.bin + +clean: + rm -rf $(IMPLMNT) synlog.tcl *.bin *.log *.log.bak + +.PHONY: all clean diff --git a/interface2/fpga/rtl/icecube2_env.sh b/interface2/fpga/rtl/icecube2_env.sh new file mode 100755 index 0000000..c246f3c --- /dev/null +++ b/interface2/fpga/rtl/icecube2_env.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +export ICECUBE_DIR="/opt/icecube2" +export SBT_DIR="$ICECUBE_DIR/sbt_backend" + +export FOUNDRY="$ICECUBE_DIR/LSE" +export SYNPLIFY_PATH="$ICECUBE_DIR/synpbase" +export LM_LICENSE_FILE="$ICECUBE_DIR/license.dat" + +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$SBT_DIR/bin/linux/opt:$SBT_DIR/bin/linux/opt/synpwrap:$SBT_DIR/lib/linux/opt:$FOUNDRY/bin/lin64" + +# Give precedence to iCEcube2 tools. +export PATH="$SBT_DIR/bin/linux/opt:$SBT_DIR/bin/linux/opt/synpwrap${PATH:+:}$PATH" + +$* diff --git a/interface2/fpga/rtl/icecube2_flow.tcl b/interface2/fpga/rtl/icecube2_flow.tcl new file mode 100755 index 0000000..f83f760 --- /dev/null +++ b/interface2/fpga/rtl/icecube2_flow.tcl @@ -0,0 +1,6 @@ +#!/usr/bin/tclsh8.5 + +# Place and route, bitmap generation and timing +source [file join $::env(SBT_DIR) "tcl/sbt_backend_synpl.tcl"] + +run_sbt_backend_auto iCE40UP5K-SG48 top [pwd] coax_Implmnt ":edifparser -y pins.pcf" coax diff --git a/interface2/fpga/rtl/pins.pcf b/interface2/fpga/rtl/pins.pcf new file mode 100644 index 0000000..2ba4825 --- /dev/null +++ b/interface2/fpga/rtl/pins.pcf @@ -0,0 +1,25 @@ +set_io clk 37 + +set_io reset_n 20 + +# SPI +set_io spi_sck 15 + +set_io spi_cs_n 16 +set_io spi_sdi 17 +set_io spi_sdo 14 + +# TX +set_io tx_active 35 +set_io tx_n 36 +set_io tx_delay 34 + +# RX +set_io rx 26 + +set_io irq 13 + +set_io gpio0 46 +set_io gpio1 47 +set_io gpio2 48 +set_io gpio3 6 diff --git a/interface2/fpga/rtl/spi_device.v b/interface2/fpga/rtl/spi_device.v new file mode 100644 index 0000000..193efe1 --- /dev/null +++ b/interface2/fpga/rtl/spi_device.v @@ -0,0 +1,79 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module spi_device ( + input clk, + input spi_sck, + input spi_cs_n, + input spi_sdi, + output spi_sdo, + output reg [7:0] rx_data, + output reg rx_strobe, + input [7:0] tx_data, + input tx_strobe +); + reg [1:0] cs_n_d; + reg [2:0] sck_d; + reg [2:0] sdi_d; + + always @(posedge clk) + begin + cs_n_d <= { cs_n_d[0], spi_cs_n }; + + sck_d <= { sck_d[1:0], spi_sck }; + sdi_d <= { sdi_d[1:0], spi_sdi }; + end + + reg [3:0] counter; + reg [7:0] input_data; + reg [7:0] output_data; + + always @(posedge clk) + begin + rx_strobe <= 0; + + if (tx_strobe) + output_data <= tx_data; + + if (cs_n_d[1]) + begin + counter <= 0; + end + else + begin + if (!sck_d[2] && sck_d[1]) + begin + input_data <= { input_data[6:0], sdi_d[2] }; + counter <= counter + 1; + end + + if (sck_d[2] && !sck_d[1]) + begin + output_data <= { output_data[6:0], 1'b0 }; + + if (counter == 8) + begin + rx_data <= input_data; + rx_strobe <= 1; + + counter <= 0; + end + end + end + end + + assign spi_sdo = output_data[7]; +endmodule diff --git a/interface2/fpga/rtl/strobe_cdc.v b/interface2/fpga/rtl/strobe_cdc.v new file mode 100644 index 0000000..c38ca95 --- /dev/null +++ b/interface2/fpga/rtl/strobe_cdc.v @@ -0,0 +1,42 @@ +// Copyright (c) 2020, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module strobe_cdc ( + input clk_in, + input strobe_in, + input clk_out, + output reg strobe_out +); + reg toggle_in; + + always @(posedge clk_in) + begin + if (strobe_in) + toggle_in <= ~toggle_in; + end + + reg [2:0] toggle_out; + + always @(posedge clk_out) + begin + toggle_out <= { toggle_out[1:0], toggle_in }; + + strobe_out <= 0; + + if (toggle_out[2] != toggle_out[1]) + strobe_out <= 1; + end +endmodule diff --git a/interface2/fpga/rtl/third_party/fifo_sync_ram.v b/interface2/fpga/rtl/third_party/fifo_sync_ram.v new file mode 100644 index 0000000..1da442b --- /dev/null +++ b/interface2/fpga/rtl/third_party/fifo_sync_ram.v @@ -0,0 +1,161 @@ +// https://raw.githubusercontent.com/smunaut/ice40-playground/68ac87f6c458712a41d5b8e305d222849233ff00/cores/misc/rtl/fifo_sync_ram.v + +/* + * fifo_sync_ram.v + * + * vim: ts=4 sw=4 + * + * Copyright (C) 2019 Sylvain Munaut + * All rights reserved. + * + * BSD 3-clause, see LICENSE.bsd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +`default_nettype none + +module fifo_sync_ram #( + parameter integer DEPTH = 256, + parameter integer WIDTH = 16 +)( + input wire [WIDTH-1:0] wr_data, + input wire wr_ena, + output wire wr_full, + + output wire [WIDTH-1:0] rd_data, + input wire rd_ena, + output wire rd_empty, + + input wire clk, + input wire rst +); + + localparam AWIDTH = $clog2(DEPTH); + + + // Signals + // ------- + + // RAM + reg [AWIDTH-1:0] ram_wr_addr; + wire [ WIDTH-1:0] ram_wr_data; + wire ram_wr_ena; + + reg [AWIDTH-1:0] ram_rd_addr; + wire [ WIDTH-1:0] ram_rd_data; + wire ram_rd_ena; + + // Fill-level + reg [AWIDTH:0] level; + (* keep="true" *) wire lvl_dec; + (* keep="true" *) wire lvl_mov; + wire lvl_empty; + + // Full + wire full_nxt; + reg full; + + // Read logic + reg rd_valid; + + + // Fill level counter + // ------------------ + // (counts the number of used words - 1) + + always @(posedge clk or posedge rst) + if (rst) + level <= {(AWIDTH+1){1'b1}}; + else + level <= level + { {AWIDTH{lvl_dec}}, lvl_mov }; + + assign lvl_dec = ram_rd_ena & ~ram_wr_ena; + assign lvl_mov = ram_rd_ena ^ ram_wr_ena; + assign lvl_empty = level[AWIDTH]; + + + // Full flag generation + // -------------------- + + assign full_nxt = level == { 1'b0, {(AWIDTH-2){1'b1}}, 2'b01 }; + + always @(posedge clk or posedge rst) + if (rst) + full <= 1'b0; + else + full <= (full | (wr_ena & ~rd_ena & full_nxt)) & ~(rd_ena & ~wr_ena); + + assign wr_full = full; + + + // Write + // ----- + + always @(posedge clk or posedge rst) + if (rst) + ram_wr_addr <= 0; + else if (ram_wr_ena) + ram_wr_addr <= ram_wr_addr + 1; + + assign ram_wr_data = wr_data; + assign ram_wr_ena = wr_ena; + + + // Read + // ---- + + always @(posedge clk or posedge rst) + if (rst) + ram_rd_addr <= 0; + else if (ram_rd_ena) + ram_rd_addr <= ram_rd_addr + 1; + + assign ram_rd_ena = (rd_ena | ~rd_valid) & ~lvl_empty; + + always @(posedge clk or posedge rst) + if (rst) + rd_valid <= 1'b0; + else if (rd_ena | ~rd_valid) + rd_valid <= ~lvl_empty; + + assign rd_data = ram_rd_data; + assign rd_empty = ~rd_valid; + + + // RAM + // --- + + ram_sdp #( + .AWIDTH(AWIDTH), + .DWIDTH(WIDTH) + ) ram_I ( + .wr_addr(ram_wr_addr), + .wr_data(ram_wr_data), + .wr_ena(ram_wr_ena), + .rd_addr(ram_rd_addr), + .rd_data(ram_rd_data), + .rd_ena(ram_rd_ena), + .clk(clk) + ); +endmodule // fifo_sync_ram diff --git a/interface2/fpga/rtl/third_party/ram_sdp.v b/interface2/fpga/rtl/third_party/ram_sdp.v new file mode 100644 index 0000000..43a845d --- /dev/null +++ b/interface2/fpga/rtl/third_party/ram_sdp.v @@ -0,0 +1,73 @@ +// https://raw.githubusercontent.com/smunaut/ice40-playground/68ac87f6c458712a41d5b8e305d222849233ff00/cores/misc/rtl/ram_sdp.v + +/* + * ram_sdp.v + * + * vim: ts=4 sw=4 + * + * Copyright (C) 2019 Sylvain Munaut + * All rights reserved. + * + * BSD 3-clause, see LICENSE.bsd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +`default_nettype none + +module ram_sdp #( + parameter integer AWIDTH = 9, + parameter integer DWIDTH = 8 +)( + input wire [AWIDTH-1:0] wr_addr, + input wire [DWIDTH-1:0] wr_data, + input wire wr_ena, + + input wire [AWIDTH-1:0] rd_addr, + output reg [DWIDTH-1:0] rd_data, + input wire rd_ena, + + input wire clk +); + // Signals + reg [DWIDTH-1:0] ram [(1<