diff --git a/.gitignore b/.gitignore index 3cb0a2f14..f5a4ebccd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ __pycache__ *.csv .vscode *.swp + +!.vscode/LHR.code-workspace +!.vscode/c_cpp_properties.json diff --git a/.vscode/LHR.code-workspace b/.vscode/LHR.code-workspace new file mode 100644 index 000000000..47e245e40 --- /dev/null +++ b/.vscode/LHR.code-workspace @@ -0,0 +1,298 @@ +{ + "folders": [ + { + "path": "../" + }, + { + "path": "../../Embedded-Sharepoint" + }, + { + "path": "../../BPS" + } + ], + "settings": { + "liveServer.settings.multiRootWorkspaceName": "renode", + "terminal.integrated.defaultProfile.linux": "bash", + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "icon": "terminal-bash", + "args": ["-i"] + }, + }, + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "Build Controls", + "type": "process", + "command": "make", + "args": [ + "${input:target}", + "TEST=${input:test}", + "DEBUG=${input:debug}" + ], + "presentation": { + "echo": false, + "reveal": "always", + "panel": "dedicated", + "focus": true, + "clear": true, + "group": "build" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [] + }, + { + "label": "Start Renode", + "type": "shell", + "command": "${workspaceFolder:Controls}/Scripts/start_renode.sh", + "presentation": { + "echo": false, + "reveal": "always", + "panel": "dedicated", + "focus": true, + "clear": true, + "group": "debug" + }, + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "pattern": { + "regexp": ".", + "file": 1, + "location": 2, + "message": 3 + }, + "background": { + "activeOnStart": true, + "beginsPattern": "^.*", + "endsPattern": "^\"Renode Simulator is now active\".*" + } + } + }, + { + "label": "Open UART2 Telnet", + "type": "shell", + "command": "echo \"Controls Leaderboard UART2\"; while ! nc -z localhost ${RENODE_UART2_TELNET}; do sleep 2; echo .; done; echo Connected && nc localhost ${RENODE_UART2_TELNET}", + "presentation": { + "echo": false, + "reveal": "always", + "panel": "dedicated", + "focus": true, + "group": "debug" + }, + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "pattern": { + "regexp": ".", + "file": 1, + "location": 2, + "message": 3 + }, + "background": { + "activeOnStart": true, + "beginsPattern": ".", + "endsPattern": "." + } + } + }, + { + "label": "Start OpenOCD debugger", + "type": "shell", + "command": "openocd", + "presentation": { + "echo": false, + "reveal": "always", + "panel": "dedicated", + "focus": true, + "group": "debug" + }, + "problemMatcher": [] + }, + { + "label": "Open Terminal GDB", + "type": "shell", + "command": "arm-none-eabi-gdb ${workspaceFolder:Controls}/Objects/controls-leader.elf", + "presentation": { + "echo": false, + "reveal": "always", + "panel": "dedicated", + "focus": true, + "group": "debug" + }, + "problemMatcher": [] + }, + { + "label": "Start Renode Tools", + "dependsOn": [ + "Start Renode", + "Open UART2 Telnet" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Start Renode Tools & Terminal GDB", + "dependsOn": [ + "Start Renode Tools", + "Open Terminal GDB" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Start Hardware Tools", + "dependsOn": [ + "Start OpenOCD debugger", + "Open Terminal GDB" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Build Controls & Start OpenOCD", + "dependsOn": [ + "Build Controls", + "Start OpenOCD debugger" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Build Controls & Start Hardware Tools", + "dependsOn": [ + "Build Controls", + "Start Hardware Tools" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Build Controls & Start Renode Tools", + "dependsOn": [ + "Build Controls", + "Start Renode Tools" + ], + "dependsOrder": "sequence", + "problemMatcher": [] + }, + { + "label": "Kill Processes", + "type": "process", + "command": [ + "${command:workbench.action.tasks.terminate}", + "${command:workbench.action.acceptSelectedQuickOpenItem}" + ], + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "target", + "type": "pickString", + "description": "Target to compile.", + "options": [ + "leader", + "flash", + "clean" + ] + }, + { + "id": "test", + "type": "promptString", + "description": "Test file to compile and run.", + "default": "" + }, + { + "id": "debug", + "type": "pickString", + "description": "Debug ", + "options": [ + "1", + "0" + ], + "default": "1" + } + ], + }, + "launch": { + "version": "2.0.0", + "configurations": [ + { + "name": "Renode Build & Debug Controls", + "type": "cppdbg", + "request": "launch", + "cwd": "${workspaceFolder:Controls}", + "program": "${workspaceFolder:Controls}/Objects/controls-leader.elf", + "preLaunchTask": "Build Controls & Start Renode Tools", + "postDebugTask": "Kill Processes", + + "stopAtEntry": true, + "stopAtConnect": true, + + "customLaunchSetupCommands": [ + {"text": "target extended-remote :3333", "ignoreFailures": false}, + {"text": "file Objects/controls-leader.elf"} + ], + + "MIMode": "gdb", + "miDebuggerPath": "arm-none-eabi-gdb", + "miDebuggerServerAddress": "localhost:3333", + "miDebuggerArgs": "--cd=${workspaceFolder:Controls}", + "hardwareBreakpoints": {"require": true}, + + "targetArchitecture": "arm64", + "logging": { + "engineLogging": false, + "traceResponse": false + } + }, + { + "name": "Hardware Build & Debug Controls", + "type": "cppdbg", + "request": "launch", + "cwd": "${workspaceFolder:Controls}", + "program": "${workspaceFolder:Controls}/Objects/controls-leader.elf", + "preLaunchTask": "Build Controls & Start OpenOCD", + "postDebugTask": "Kill Processes", + + "stopAtEntry": true, + "stopAtConnect": true, + + "customLaunchSetupCommands": [ + {"text": "target extended-remote :3333", "ignoreFailures": false}, + {"text": "file Objects/controls-leader.elf"} + ], + + "MIMode": "gdb", + "miDebuggerPath": "arm-none-eabi-gdb", + "miDebuggerServerAddress": "localhost:3333", + "miDebuggerArgs": "--cd=${workspaceFolder:Controls}", + "hardwareBreakpoints": {"require": true}, + + "targetArchitecture": "arm64", + "logging": { + "engineLogging": false, + "traceResponse": false + } + } + + ] + }, + "extensions": { + "recommendations": [ + "ms-vscode.cpptools-extension-pack", // For Controls C code + "GitHub.vscode-pull-request-github", // For reviewing pull requests directly from VSCode + "xaver.clang-format", // For auto-formatting code on VSCode + "eamodio.gitlens", // For better github stuff + "ritwickdey.liveserver", // For quick viewing test reports + ] + } + +} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 4b6ca044e..95b093be7 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -6,23 +6,18 @@ "${workspaceFolder}/**", "${workspaceFolder}/Apps/Inc", "${workspaceFolder}/Apps/Src", - "${workspaceFolder}/Drivers/Inc", "${workspaceFolder}/Drivers/Src", - "${workspaceFolder}/Config/Inc", - "${workspaceFolder}/BSP/STM32F413/Src", + "${workspaceFolder}/BSP/Inc", "${workspaceFolder}/BSP/STM32F413/STM32F4xx_StdPeriph_Driver/Src", "${workspaceFolder}/BSP/STM32F413/STM32F4xx_StdPeriph_Driver/Inc", - "${workspaceFolder}/BSP/Template/Src", - "${workspaceFolder}/RTOS/uCOS-III-STM32F4/uC-CPU", "${workspaceFolder}/RTOS/uCOS-III-STM32F4/uC-CPU/ARM-Cortex-M4/GNU", "${workspaceFolder}/RTOS/uCOS-III-STM32F4/uC-LIB", "${workspaceFolder}/RTOS/uCOS-III-STM32F4/uCOS-III/Source", "${workspaceFolder}/RTOS/uCOS-III-STM32F4/uCOS-III/Ports/ARM-Cortex-M4/Generic/GNU", - "${workspaceFolder}/CMSIS/Include", "${workspaceFolder}/CMSIS/Device/ST/STM32F4xx/Include" ], @@ -32,7 +27,6 @@ ], "compilerPath": "/usr/bin/gcc", "cStandard": "c11", - "cppStandard": "c++17", "intelliSenseMode": "clang-x64" } ], diff --git a/Apps/Inc/Tasks.h b/Apps/Inc/Tasks.h index a43860440..8d02dd1ea 100644 --- a/Apps/Inc/Tasks.h +++ b/Apps/Inc/Tasks.h @@ -180,7 +180,10 @@ void throwTaskError(error_code_t errorCode, callback_t errorCallback, error_sche void _assertOSError (OS_ERR err); //TODO: This should be changed to enforce only enum usage #if DEBUG == 1 -#define assertOSError(err) +#define assertOSError(err) \ + if (err != OS_ERR_NONE) { \ + printf("Error asserted at %s, line %d: %d\n\r", __FILE__, __LINE__, err); \ + } \ _assertOSError(err); #else #define assertOSError(err) _assertOSError(err); diff --git a/Apps/Src/Tasks.c b/Apps/Src/Tasks.c index 9e7022a80..ede597726 100644 --- a/Apps/Src/Tasks.c +++ b/Apps/Src/Tasks.c @@ -104,9 +104,7 @@ void throwTaskError(error_code_t errorCode, callback_t errorCallback, error_sche while(1) { #if DEBUG == 1 - // Print the error that caused this fault - printf("\n\rCurrent Error Location: 0x%04x", OSErrLocBitmap); printf("\n\rCurrent Error Code: 0x%04x\n\r", errorCode); // Print the errors for each applications with error data diff --git a/BSP/STM32F413/Makefile b/BSP/STM32F413/Makefile index 98e7eae9a..987b35b87 100644 --- a/BSP/STM32F413/Makefile +++ b/BSP/STM32F413/Makefile @@ -8,7 +8,11 @@ TARGET = controls-leader # building variables ###################################### # optimization -OPT = -Og -g +ifeq ($(DEBUG), 0) +OPT = -O3 +else +OPT = -Og -g3 +endif ####################################### # paths @@ -32,15 +36,10 @@ $(wildcard ../../RTOS/uCOS-III-STM32F4/uC-CPU/*.c) \ $(wildcard ../../RTOS/uCOS-III-STM32F4/uC-CPU/ARM-Cortex-M4/GNU/*.c) \ $(wildcard ../../RTOS/uCOS-III-STM32F4/uC-LIB/*.c) -ifneq ($(TEST), none) -TEST_FILE := $(TEST).c -# This line adds everything in Apps/Src/*.c except for main.c +# This line adds everything in Apps/Src/*.c except for main.c, then adds the test file C_SOURCES += \ $(filter-out ../../Apps/Src/main.c, $(wildcard ../../Apps/Src/*.c)) \ -$(wildcard ../../$(TEST_FILE)) -else -C_SOURCES += $(wildcard ../../Apps/Src/*.c) -endif +../../$(TEST) # ASM sources ASM_SOURCES = \ @@ -111,8 +110,8 @@ C_INCLUDES = \ -I../../RTOS/uCOS-III-STM32F4/uCOS-III/Ports/ARM-Cortex-M4/Generic/GNU/ \ -I../../RTOS/uCOS-III-STM32F4/uC-CPU/ \ -I../../RTOS/uCOS-III-STM32F4/uC-CPU/ARM-Cortex-M4/GNU/ \ --I../../RTOS/uCOS-III-STM32F4/uC-LIB/ - +-I../../RTOS/uCOS-III-STM32F4/uC-LIB/ \ +-I../../Tests/Inc/ \ # compile gcc flags ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections diff --git a/BSP/Template/Makefile b/BSP/Template/Makefile deleted file mode 100644 index e69de29bb..000000000 diff --git a/BSP/Template/Src/BSP_ADC.c b/BSP/Template/Src/BSP_ADC.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/BSP/Template/Src/BSP_CAN.C b/BSP/Template/Src/BSP_CAN.C deleted file mode 100644 index e69de29bb..000000000 diff --git a/BSP/Template/Src/BSP_SPI.C b/BSP/Template/Src/BSP_SPI.C deleted file mode 100644 index e69de29bb..000000000 diff --git a/BSP/Template/Src/BSP_Switches.c b/BSP/Template/Src/BSP_Switches.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/CarSim/Test_CANFilter_BPS.c b/CarSim/Test_CANFilter_BPS.c deleted file mode 100644 index e1d31d57e..000000000 --- a/CarSim/Test_CANFilter_BPS.c +++ /dev/null @@ -1,100 +0,0 @@ -#include"Tasks.h" -#include "CANbus.h" -#include "BSP_UART.h" -#include "CANConfig.h" - - -static OS_TCB TaskBPS_TCB; -static CPU_STK TaskBPS_Stk[128]; -#define STACK_SIZE 128 - -#define CARCAN_FILTER_SIZE (sizeof carCANFilterList / sizeof(CANId_t)) -#define CANMSG_ARR_SIZE (sizeof(CANMsgs) / sizeof(CANMsgs[0])) - -// Test CANbus hardware filtering by flooding the bus with messages -void Task_BPS(void *p_arg){ - CPU_Init(); - OS_CPU_SysTickInit(SystemCoreClock / (CPU_INT32U) OSCfg_TickRate_Hz); - OS_ERR err; - // CANbus_Init(CARCAN, carCANFilterList, CARCAN_FILTER_SIZE); - CANbus_Init(CARCAN, carCANFilterList, 0); - - // An array consisting of messages we read with random "noise" messages interspersed - int CANMsgs[] = { - BPS_TRIP, - CHARGE_ENABLE, - STATE_OF_CHARGE, - SUPPLEMENTAL_VOLTAGE, - MOTOR_DRIVE, - MOTOR_POWER, - MOTOR_RESET, - MOTOR_STATUS, - MC_BUS, - VELOCITY, - MC_PHASE_CURRENT, - VOLTAGE_VEC, - CURRENT_VEC, - BACKEMF, - TEMPERATURE, - ODOMETER_AMPHOURS, - ARRAY_CONTACTOR_STATE_CHANGE, - CARDATA - }; - - // Make a CAN message. Message id is set in the for loop - CANDATA_t msg; - msg.idx = 0; - *(uint64_t*)(&msg.data) = 0; // Just an empty message without data - - - - while(1){ - - for (uint8_t i = 0; i < CANMSG_ARR_SIZE; i++) { - msg.ID = CANMsgs[i]; - CANbus_Send(msg, true, CARCAN); // Send the current message - printf("Sent %d\n\r", msg.ID); //print the id to the uart - OSTimeDlyHMSM(0, 0, 0, 100, OS_OPT_TIME_HMSM_STRICT, &err); - } - - } - -} - - - -int main(void){ //OS initialization and task spawning - OS_ERR err; - OSInit(&err); - if(err != OS_ERR_NONE){ - printf("OS error code %d\n\r", err); - } - - BSP_UART_Init(UART_2); - - OSTaskCreate( - (OS_TCB*)&TaskBPS_TCB, - (CPU_CHAR*)"TaskBPS", - (OS_TASK_PTR)Task_BPS, - (void*)NULL, - (OS_PRIO)3, - (CPU_STK*)TaskBPS_Stk, - (CPU_STK_SIZE)STACK_SIZE, - (CPU_STK_SIZE)STACK_SIZE, - (OS_MSG_QTY)0, - (OS_TICK)NULL, - (void*)NULL, - (OS_OPT)(OS_OPT_TASK_STK_CLR|OS_OPT_TASK_STK_CHK), - (OS_ERR*)&err - ); - - if (err != OS_ERR_NONE) { - printf("TaskBPS error code %d\n\r", err); - } - OSStart(&err); - if (err != OS_ERR_NONE) { - printf("OS error code %d\n\r", err); - } - return 0; - -} diff --git a/CarSim/Test_CarSim.c b/CarSim/Test_CarSim.c deleted file mode 100644 index aefa1d97d..000000000 --- a/CarSim/Test_CarSim.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -int main(){ - printf("Hello World"); - return 0; -} \ No newline at end of file diff --git a/CarSim/Test_Renode_Car_CANBPSFault.c b/CarSim/Test_Renode_Car_CANBPSFault.c deleted file mode 100644 index 1ffbd1041..000000000 --- a/CarSim/Test_Renode_Car_CANBPSFault.c +++ /dev/null @@ -1,107 +0,0 @@ -/** - * This is meant to test the ReadCarCAN module in the controls system, by "pretending" to be BPS. - * - * This testfile is intended to be compiled and run on Renode as the supplementary machine to send CAN messages to the main machine. - * It is designed to send messages on CAN1 (CARCAN) to test ReadCarCAN's fault handling - * Specifically, it sends the BPS trip message so we can check that this message sends the car to Fault State - * -*/ - - -#include "Tasks.h" -#include "CANbus.h" - -static OS_TCB Task1_TCB; -static CPU_STK Task1_Stk[128]; -#define STACK_SIZE 128 - - - -void Task1(void *p_arg){ - CPU_Init(); - OS_CPU_SysTickInit(SystemCoreClock / (CPU_INT32U) OSCfg_TickRate_Hz); - OS_ERR err; - CANbus_Init(CARCAN, NULL, 0); - - - - //send enable messages on a loop on time - - // Message for charge enable - CANDATA_t chargeMsg; - chargeMsg.ID = CHARGE_ENABLE; - *(uint64_t*)(&chargeMsg.data) = 0; - chargeMsg.idx = 0; - - // Message for BPS Fault - CANDATA_t tripBPSMsg; - tripBPSMsg.ID = BPS_TRIP; - *(uint64_t*)(&tripBPSMsg.data) = 0; - tripBPSMsg.idx = 0; - - - while(1){ - chargeMsg.data[0] = true; - for(int i = 0; i<10; i++){ - CANbus_Send(chargeMsg, CAN_BLOCKING,CARCAN); - OSTimeDlyHMSM(0, 0, 0, 400, OS_OPT_TIME_HMSM_STRICT, &err); - printf("\nSent chargeMsg %d", i); - } - - CANbus_Send(tripBPSMsg, CAN_BLOCKING, CARCAN); - printf("\nSent trip message %d", tripBPSMsg.data[0]); - - - for(int i = 0; i<10; i++){ - CANbus_Send(chargeMsg, CAN_BLOCKING,CARCAN); - OSTimeDlyHMSM(0, 0, 0, 400, OS_OPT_TIME_HMSM_STRICT, &err); - } - - *(uint64_t*)(&tripBPSMsg.data) = 1; - CANbus_Send(tripBPSMsg, CAN_BLOCKING, CARCAN); - - } - -} - -int main(void){ //startup OS stuff, spawn test task - - OS_ERR err; - OSInit(&err); - if(err != OS_ERR_NONE){ - printf("OS error code %d\n",err); - } - - BSP_UART_Init(UART_2); - - OSTaskCreate( - (OS_TCB*)&Task1_TCB, - (CPU_CHAR*)"Task1", - (OS_TASK_PTR)Task1, - (void*)NULL, - (OS_PRIO)4, - (CPU_STK*)Task1_Stk, - (CPU_STK_SIZE)STACK_SIZE/10, - (CPU_STK_SIZE)STACK_SIZE, - (OS_MSG_QTY)0, - (OS_TICK)NULL, - (void*)NULL, - (OS_OPT)(OS_OPT_TASK_STK_CLR|OS_OPT_TASK_STK_CHK), - (OS_ERR*)&err - ); - - if (err != OS_ERR_NONE) { - printf("Task error code %d\n", err); - } - OSStart(&err); - if (err != OS_ERR_NONE) { - printf("OS error code %d\n", err); - } - return 0; -} - - - - - - diff --git a/CarSim/Test_car-sim.c b/CarSim/Test_car-sim.c deleted file mode 100644 index aefa1d97d..000000000 --- a/CarSim/Test_car-sim.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -int main(){ - printf("Hello World"); - return 0; -} \ No newline at end of file diff --git a/Makefile b/Makefile index 8b15e4482..3439a0040 100644 --- a/Makefile +++ b/Makefile @@ -10,48 +10,27 @@ DARKGRAY=\033[1;30m YELLOW=\033[0;33m NC=\033[0m # No Color -TEST_LEADER = none -TEST_MOTOR = none -TEST_CAR = none - -DEBUG = 0 +DEBUG ?= 1 export DEBUG +# Check if test file exists for the leader. +ifneq (,$(wildcard Tests/Test_$(TEST).c)) + TEST_LEADER ?= Tests/Test_$(TEST).c +else + TEST_LEADER ?= Apps/Src/main.c +endif + LEADER = controls-leader -MOTORSIM = motor-sim -CARSIM = car-sim all: @echo "${RED}Not enough arguments. Call: ${ORANGE}make help${NC}" -simulator: leader motor-sim car-sim - @echo "${BLUE}Compiled for simulator! Jolly Good!${NC}" - +.PHONY: stm32f413 leader: @echo "${YELLOW}Compiling for leader...${NC}" -ifeq ($(TEST_LEADER), none) - $(MAKE) -C BSP -C STM32F413 -j TARGET=$(LEADER) TEST=none -else - $(MAKE) -C BSP -C STM32F413 -j TARGET=$(LEADER) TEST=Tests/Test_$(TEST_LEADER) -endif + $(MAKE) -C BSP -C STM32F413 -j TARGET=$(LEADER) TEST=$(TEST_LEADER) @echo "${BLUE}Compiled for leader! Jolly Good!${NC}" -motor-sim: -ifneq ($(TEST_MOTOR), none) - @echo "${YELLOW}Compiling for motor sim...${NC}" - $(MAKE) -C BSP -C STM32F413 -j TARGET=$(MOTORSIM) TEST=MotorSim/Test_$(TEST_MOTOR) - @echo "${BLUE}Compiled for motor sim! Jolly Good!${NC}" -endif - -car-sim: - @echo "${YELLOW}Compiling for car sim...${NC}" -ifneq ($(TEST_CAR), none) - $(MAKE) -C BSP -C STM32F413 -j TARGET=$(CARSIM) TEST=CarSim/Test_$(TEST_CAR) - @echo "${BLUE}Compiled for car sim! Jolly Good!${NC}" -endif - -stm32f413: leader - flash: $(MAKE) -C BSP -C STM32F413 flash @@ -62,8 +41,7 @@ docs: help: @echo "Format: ${ORANGE}make ${BLUE}${NC}${ORANGE}TEST=${PURPLE}${NC}" @echo "BSP types (required):" - @echo " ${BLUE}simulator${NC}" - @echo " ${BLUE}stm32f413${NC}" + @echo " ${BLUE}stm32f413/leader${NC}" @echo "" @echo "Test types (optional):" @echo " Set TEST only if you want to build a test." diff --git a/MotorSim/Test_MotorSim.c b/MotorSim/Test_MotorSim.c deleted file mode 100644 index aefa1d97d..000000000 --- a/MotorSim/Test_MotorSim.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -int main(){ - printf("Hello World"); - return 0; -} \ No newline at end of file diff --git a/MotorSim/Test_motor-sim.c b/MotorSim/Test_motor-sim.c deleted file mode 100644 index aefa1d97d..000000000 --- a/MotorSim/Test_motor-sim.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -int main(){ - printf("Hello World"); - return 0; -} \ No newline at end of file diff --git a/README.md b/README.md index 879c11ddc..8b0038bd1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ The system can be built and deployed from a terminal. - C/C++ - ARM - cortex-debug +6. Add ```source /path/to/Controls/Scripts/load_env_vars.sh``` to the end of your ~/.bashrc file in order to load the necessary environment variables on shell startup. For example, mine is ```source /${HOME}/LHR/Controls/Scripts/load_env_vars.sh``` ## Building When calling any of the following commands, make sure you are in the Controls folder. diff --git a/Renode/STM32DMA_Fix.cs b/Renode/STM32DMA_Fix.cs new file mode 100644 index 000000000..f8f450797 --- /dev/null +++ b/Renode/STM32DMA_Fix.cs @@ -0,0 +1,454 @@ +// +// Copyright (c) 2010-2023 Antmicro +// Copyright (c) 2011-2015 Realtime Embedded +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Logging; +using Antmicro.Renode.Core; +using System.Collections.Generic; +using System.Linq; + +namespace Antmicro.Renode.Peripherals.DMA +{ + public sealed class STM32DMA_Fix : IDoubleWordPeripheral, IKnownSize, IGPIOReceiver, INumberedGPIOOutput + { + public STM32DMA_Fix(Machine machine) + { + streamFinished = new bool[NumberOfStreams]; + streams = new Stream[NumberOfStreams]; + for(var i = 0; i < streams.Length; i++) + { + streams[i] = new Stream(this, i); + } + this.machine = machine; + engine = new DmaEngine(machine.GetSystemBus(this)); + Reset(); + } + + public IReadOnlyDictionary Connections + { + get + { + var i = 0; + return streams.ToDictionary(x => i++, y => (IGPIO)y.IRQ); + } + } + + public long Size + { + get + { + return 0x400; + } + } + + public uint ReadDoubleWord(long offset) + { + switch((Registers)offset) + { + case Registers.LowInterruptStatus: + case Registers.HighInterruptStatus: + return HandleInterruptRead((int)(offset/4)); + default: + if(offset >= StreamOffsetStart && offset <= StreamOffsetEnd) + { + offset -= StreamOffsetStart; + return streams[offset / StreamSize].Read(offset % StreamSize); + } + this.LogUnhandledRead(offset); + return 0; + } + } + + public void WriteDoubleWord(long offset, uint value) + { + switch((Registers)offset) + { + case Registers.LowInterruptClear: + case Registers.HighInterruptClear: + HandleInterruptClear((int)((offset - 8)/4), value); + break; + default: + if(offset >= StreamOffsetStart && offset <= StreamOffsetEnd) + { + offset -= StreamOffsetStart; + streams[offset / StreamSize].Write(offset % StreamSize, value); + } + else + { + this.LogUnhandledWrite(offset, value); + } + break; + } + } + + public void Reset() + { + streamFinished.Initialize(); + foreach(var stream in streams) + { + stream.Reset(); + } + } + + public void OnGPIO(int number, bool value) + { + if(number < 0 || number >= streams.Length) + { + this.Log(LogLevel.Error, "Attempted to start non-existing DMA stream number: {0}. Maximum value is {1}", number, streams.Length); + return; + } + + if(value) + { + this.Log(LogLevel.Debug, "DMA peripheral request on stream {0} {1}", number, value); + if(streams[number].Enabled) + { + streams[number].DoPeripheralTransfer(); + } + else + { + this.Log(LogLevel.Warning, "DMA peripheral request on stream {0} ignored", number); + } + } + } + + private uint HandleInterruptRead(int offset) + { + lock(streamFinished) + { + var returnValue = 0u; + for(var i = 4 * offset; i < 4 * (offset + 1); i++) + { + if(streamFinished[i]) + { + returnValue |= 1u << BitNumberForStream(i - 4 * offset); + } + } + return returnValue; + } + } + + private void HandleInterruptClear(int offset, uint value) + { + lock(streamFinished) + { + for(var i = 4 * offset; i < 4 * (offset + 1); i++) + { + var bitNo = BitNumberForStream(i - 4 * offset); + if((value & (1 << bitNo)) != 0) + { + streamFinished[i] = false; + streams[i].IRQ.Unset(); + } + } + } + } + + private static int BitNumberForStream(int streamNo) + { + switch(streamNo) + { + case 0: + return 5; + case 1: + return 11; + case 2: + return 21; + case 3: + return 27; + default: + throw new InvalidOperationException("Should not reach here."); + } + } + + private readonly bool[] streamFinished; + private readonly Stream[] streams; + private readonly DmaEngine engine; + private readonly Machine machine; + + private const int NumberOfStreams = 8; + private const int StreamOffsetStart = 0x10; + private const int StreamOffsetEnd = 0xCC; + private const int StreamSize = 0x18; + + private enum Registers + { + LowInterruptStatus = 0x0, // DMA_LISR + HighInterruptStatus = 0x4, // DMA_HISR + LowInterruptClear = 0x8, //DMA_LIFCR + HighInterruptClear = 0xC // DMA_HIFCR + } + + private class Stream + { + public Stream(STM32DMA_Fix parent, int streamNo) + { + this.parent = parent; + this.streamNo = streamNo; + IRQ = new GPIO(); + } + + public uint Read(long offset) + { + switch((Registers)offset) + { + case Registers.Configuration: + return HandleConfigurationRead(); + case Registers.NumberOfData: + return (uint)numberOfData; + case Registers.PeripheralAddress: + return peripheralAddress; + case Registers.Memory0Address: + return memory0Address; + case Registers.Memory1Address: + return memory1Address; + default: + parent.Log(LogLevel.Warning, "Unexpected read access from not implemented register (offset 0x{0:X}).", offset); + return 0; + } + } + + public void Write(long offset, uint value) + { + switch((Registers)offset) + { + case Registers.Configuration: + HandleConfigurationWrite(value); + break; + case Registers.NumberOfData: + numberOfData = (int)value; + bufferSize = numberOfData; + break; + case Registers.PeripheralAddress: + peripheralAddress = value; + break; + case Registers.Memory0Address: + memory0Address = value; + break; + case Registers.Memory1Address: + memory1Address = value; + break; + default: + parent.Log(LogLevel.Warning, "Unexpected write access to not implemented register (offset 0x{0:X}, value 0x{1:X}).", offset, value); + break; + } + } + + public GPIO IRQ { get; private set; } + + public void Reset() + { + memory0Address = 0u; + memory1Address = 0u; + numberOfData = 0; + bufferSize = 0; + memoryTransferType = TransferType.Byte; + peripheralTransferType = TransferType.Byte; + memoryIncrementAddress = false; + peripheralIncrementAddress = false; + circular = false; + direction = Direction.PeripheralToMemory; + interruptOnComplete = false; + Enabled = false; + } + + private Request CreateRequest(int? size = null, int? destinationOffset = null) + { + var sourceAddress = 0u; + var destinationAddress = 0u; + switch(direction) + { + case Direction.PeripheralToMemory: + case Direction.MemoryToMemory: + sourceAddress = peripheralAddress; + destinationAddress = memory0Address; + break; + case Direction.MemoryToPeripheral: + sourceAddress = memory0Address; + destinationAddress = peripheralAddress; + break; + } + + var sourceTransferType = direction == Direction.PeripheralToMemory ? peripheralTransferType : memoryTransferType; + var destinationTransferType = direction == Direction.MemoryToPeripheral ? peripheralTransferType : memoryTransferType; + var incrementSourceAddress = direction == Direction.PeripheralToMemory ? peripheralIncrementAddress : memoryIncrementAddress; + var incrementDestinationAddress = direction == Direction.MemoryToPeripheral ? peripheralIncrementAddress : memoryIncrementAddress; + return new Request(sourceAddress, (uint)(destinationAddress + (destinationOffset ?? 0)), size ?? numberOfData, sourceTransferType, destinationTransferType, + incrementSourceAddress, incrementDestinationAddress); + } + + public void DoTransfer() + { + var request = CreateRequest(); + if(request.Size > 0) + { + lock(parent.streamFinished) + { + parent.engine.IssueCopy(request); + parent.streamFinished[streamNo] = true; + if(interruptOnComplete) + { + parent.machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => IRQ.Set()); + } + } + } + } + + public void DoPeripheralTransfer() + { + var request = CreateRequest((int)memoryTransferType, (bufferSize - numberOfData) * (int)memoryTransferType); + + if(request.Size > 0) + { + lock(parent.streamFinished) + { + parent.engine.IssueCopy(request); + numberOfData -= 1; + + if(numberOfData == 0) + { + parent.streamFinished[streamNo] = true; + + if(!circular) // Disable if not circular mode + { + Enabled = false; + } + else + { + numberOfData = bufferSize; + } + + if(interruptOnComplete) + { + parent.machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => IRQ.Set()); + } + } + } + } + } + + public bool Enabled { get; private set; } + + private uint HandleConfigurationRead() + { + var returnValue = 0u; + returnValue |= (uint)(channel << 25); + returnValue |= (uint)(priority << 16); + + returnValue |= FromTransferType(memoryTransferType) << 13; + returnValue |= FromTransferType(peripheralTransferType) << 11; + returnValue |= memoryIncrementAddress ? (1u << 10) : 0u; + returnValue |= peripheralIncrementAddress ? (1u << 9) : 0u; + returnValue |= circular ? (1u << 8) : 0u; + returnValue |= ((uint)direction) << 6; + returnValue |= interruptOnComplete ? (1u << 4) : 0u; + // regarding enable bit - our transfer is always finished + return returnValue; + } + + private void HandleConfigurationWrite(uint value) + { + // we ignore channel selection and priority + channel = (byte)((value >> 25) & 7); + priority = (byte)((value >> 16) & 3); + + memoryTransferType = ToTransferType(value >> 13); + peripheralTransferType = ToTransferType(value >> 11); + memoryIncrementAddress = (value & (1 << 10)) != 0; + peripheralIncrementAddress = (value & (1 << 9)) != 0; + circular = (value & (1 << 8)) != 0; + direction = (Direction)((value >> 6) & 3); + interruptOnComplete = (value & (1 << 4)) != 0; + // we ignore transfer error interrupt enable as we never post errors + if((value & ~0xE037ED5) != 0) + { + parent.Log(LogLevel.Warning, "Channel {0}: unsupported bits written to configuration register. Value is 0x{1:X}.", streamNo, value); + } + + if((value & 1) != 0) + { + if(direction != Direction.PeripheralToMemory) + { + DoTransfer(); + } + else + { + Enabled = true; + } + } + } + + private TransferType ToTransferType(uint dataSize) + { + dataSize &= 3; + switch(dataSize) + { + case 0: + return TransferType.Byte; + case 1: + return TransferType.Word; + case 2: + return TransferType.DoubleWord; + default: + parent.Log(LogLevel.Warning, "Stream {0}: Non existitng possible value written as data size.", streamNo); + return TransferType.Byte; + } + } + + private static uint FromTransferType(TransferType transferType) + { + switch(transferType) + { + case TransferType.Byte: + return 0; + case TransferType.Word: + return 1; + case TransferType.DoubleWord: + return 2; + } + throw new InvalidOperationException("Should not reach here."); + } + + private uint memory0Address; + private uint memory1Address; + private uint peripheralAddress; + private int numberOfData; + private TransferType memoryTransferType; + private TransferType peripheralTransferType; + private bool memoryIncrementAddress; + private bool peripheralIncrementAddress; + private bool circular; + private int bufferSize; + private Direction direction; + private bool interruptOnComplete; + private byte channel; + private byte priority; + + private readonly STM32DMA_Fix parent; + private readonly int streamNo; + + private enum Registers + { + Configuration = 0x0, // DMA_SxCR + NumberOfData = 0x4, // DMA_SxNDTR + PeripheralAddress = 0x8, // DMA_SxPAR + Memory0Address = 0xC, // DMA_SxM0AR + Memory1Address = 0x10, // DMA_SxM1AR + FIFOControl = 0x14, // DMA_SxFCR + } + + private enum Direction : byte + { + PeripheralToMemory = 0, + MemoryToPeripheral = 1, + MemoryToMemory = 2 + } + } + } +} + diff --git a/Renode/STM32_ADC_Fix.cs b/Renode/STM32_ADC_Fix.cs new file mode 100644 index 000000000..eb3fb8392 --- /dev/null +++ b/Renode/STM32_ADC_Fix.cs @@ -0,0 +1,343 @@ +// +// Copyright (c) 2010-2023 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Antmicro.Renode.Core; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Exceptions; +using Antmicro.Renode.Logging; +using Antmicro.Renode.Utilities; +using Antmicro.Renode.Time; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Peripherals.Timers; + +namespace Antmicro.Renode.Peripherals.Analog +{ + // STM32 ADC has many features and only a partial subset are implemented here + // + // Supported: + // * Software triggered conversion + // * Single conversion + // * Scan mode with regular group + // * Continuous conversion + // * Modes of use + // - Polling (read EOC status flag) + // - Interrupt (enable ADC interrupt for EOC) + // - DMA (enable DMA and configure stream for peripheral to memory transfer) + // + // Not Implemented: + // * Analog watchdog + // * Overrun detection + // * External triggers + // * Injected channels + // * Sampling time (time is fixed) + // * Discontinuous mode + // * Multi-ADC (i.e. Dual/Triple) mode + [AllowedTranslations(AllowedTranslation.WordToDoubleWord)] + public class STM32_ADC_Fix : BasicDoubleWordPeripheral, IKnownSize + { + public STM32_ADC_Fix(Machine machine) : base(machine) + { + channels = Enumerable.Range(0, NumberOfChannels).Select(x => new ADCChannel(this, x)).ToArray(); + + DefineRegisters(); + + // Sampling time fixed + samplingTimer = new LimitTimer( + machine.ClockSource, 1000000, this, "samplingClock", + limit: 100, + eventEnabled: true, + direction: Direction.Ascending, + enabled: false, + autoUpdate: false, + workMode: WorkMode.OneShot); + samplingTimer.LimitReached += OnConversionFinished; + } + + public void FeedSample(uint value, uint channelIdx, int repeat = 1) + { + if(IsValidChannel(channelIdx)) + { + channels[channelIdx].FeedSample(value, repeat); + } + } + + public void FeedSample(string path, uint channelIdx, int repeat = 1) + { + if(IsValidChannel(channelIdx)) + { + var parsedSamples = ADCChannel.ParseSamplesFile(path); + channels[channelIdx].FeedSample(parsedSamples, repeat); + } + } + + private bool IsValidChannel(uint channelIdx) + { + if(channelIdx >= NumberOfChannels) + { + throw new RecoverableException("Only channels 0/1 are supported"); + } + return true; + } + + public override void Reset() + { + base.Reset(); + foreach(var c in channels) + { + c.Reset(); + } + } + + public long Size => 0x50; + + public GPIO IRQ { get; } = new GPIO(); + public GPIO DMARequest { get; } = new GPIO(); + + private void DefineRegisters() + { + Registers.Status.Define(this) + .WithTaggedFlag("Analog watchdog flag", 0) + .WithFlag(1, out endOfConversion, name: "Regular channel end of conversion") + .WithTaggedFlag("Injected channel end of conversion", 2) + .WithTaggedFlag("Injected channel start flag", 3) + .WithTaggedFlag("Regular channel start flag", 4) + .WithTaggedFlag("Overrun", 5) + .WithReservedBits(6, 26); + + Registers.Control1.Define(this) + .WithTag("Analog watchdog channel select bits", 0, 5) + .WithFlag(5, out eocInterruptEnable, name: "Interrupt enable for EOC") + .WithTaggedFlag("Analog watchdog interrupt enable", 6) + .WithTaggedFlag("Interrupt enable for injected channels", 7) + .WithFlag(8, out scanMode, name: "Scan mode") + .WithTaggedFlag("Enable the watchdog on a single channel in scan mode", 9) + .WithTaggedFlag("Automatic injected group conversion", 10) + .WithTaggedFlag("Discontinuous mode on regular channels", 11) + .WithTaggedFlag("Discontinuous mode on injected channels", 12) + .WithTag("Discontinuous mode channel count", 13, 3) + .WithReservedBits(16, 6) + .WithTaggedFlag("Analog watchdog enable on injected channels", 22) + .WithTaggedFlag("Analog watchdog enable on regular channels", 23) + .WithTag("Resolution", 24, 2) + .WithTaggedFlag("Overrun interrupt enable", 26) + .WithReservedBits(27, 5); + + Registers.Control2.Define(this, name: "Control2") + .WithFlag(0, out adcOn, + name: "A/D Converter ON/OFF", + changeCallback: (_, val) => { if(val) { EnableADC(); }}) + .WithFlag(1, out continuousConversion, name: "Continous conversion") + .WithReservedBits(2, 6) + .WithFlag(8, out dmaEnabled, name: "Direct memory access mode") + .WithFlag(9, out dmaIssueRequest, name: "DMA disable selection") + .WithFlag(10, out endOfConversionSelect, name: "End of conversion select") + .WithTaggedFlag("Data Alignment", 11) + .WithReservedBits(12, 4) + .WithTag("External event select for injected group", 16, 4) + .WithTag("External trigger enable for injected channels", 20, 2) + .WithTaggedFlag("Start conversion of injected channels", 22) + .WithReservedBits(23, 1) + .WithTag("External event select for regular group", 24, 4) + .WithTag("External trigger enable for regular channels", 28, 2) + .WithFlag(30, + name: "Start Conversion Of Regular Channels", + writeCallback: (_, value) => { if(value) StartConversion(); }, + valueProviderCallback: _ => false) + .WithReservedBits(31, 1); + + Registers.SampleTime1.Define(this) + .WithTag("Channel 10 sampling time", 0, 3) + .WithTag("Channel 11 sampling time", 3, 3) + .WithTag("Channel 12 sampling time", 6, 3) + .WithTag("Channel 13 sampling time", 9, 3) + .WithTag("Channel 14 sampling time", 12, 3) + .WithTag("Channel 15 sampling time", 15, 3) + .WithTag("Channel 16 sampling time", 18, 3) + .WithTag("Channel 17 sampling time", 21, 3) + .WithTag("Channel 18 sampling time", 24, 3) + .WithReservedBits(27, 5); + + Registers.SampleTime2.Define(this) + .WithTag("Channel 0 sampling time", 0, 3) + .WithTag("Channel 1 sampling time", 3, 3) + .WithTag("Channel 2 sampling time", 6, 3) + .WithTag("Channel 3 sampling time", 9, 3) + .WithTag("Channel 4 sampling time", 12, 3) + .WithTag("Channel 5 sampling time", 15, 3) + .WithTag("Channel 6 sampling time", 18, 3) + .WithTag("Channel 7 sampling time", 21, 3) + .WithTag("Channel 8 sampling time", 24, 3) + .WithTag("Channel 9 sampling time", 27, 3) + .WithReservedBits(30, 2); + + Registers.InjectedChannelDataOffset1.Define(this) + .WithTag("Data offset for injected channel 1", 0, 12) + .WithReservedBits(12, 20); + Registers.InjectedChannelDataOffset2.Define(this) + .WithTag("Data offset for injected channel 2", 0, 12) + .WithReservedBits(12, 20); + Registers.InjectedChannelDataOffset3.Define(this) + .WithTag("Data offset for injected channel 3", 0, 12) + .WithReservedBits(12, 20); + Registers.InjectedChannelDataOffset4.Define(this) + .WithTag("Data offset for injected channel 4", 0, 12) + .WithReservedBits(12, 20); + + Registers.RegularSequence1.Define(this) + .WithValueField(0, 5, out regularSequence[12], name: "13th conversion in regular sequence") + .WithValueField(5, 5, out regularSequence[13], name: "14th conversion in regular sequence") + .WithValueField(10, 5, out regularSequence[14], name: "15th conversion in regular sequence") + .WithValueField(15, 5, out regularSequence[15], name: "16th conversion in regular sequence") + .WithValueField(20, 4, writeCallback: (_, val) => { regularSequenceLen = (uint)val + 1; }, name: "Regular channel sequence length"); + + Registers.RegularSequence2.Define(this) + .WithValueField(0, 5, out regularSequence[6], name: "7th conversion in regular sequence") + .WithValueField(5, 5, out regularSequence[7], name: "8th conversion in regular sequence") + .WithValueField(10, 5, out regularSequence[8], name: "9th conversion in regular sequence") + .WithValueField(15, 5, out regularSequence[9], name: "10th conversion in regular sequence") + .WithValueField(20, 5, out regularSequence[10], name: "11th conversion in regular sequence") + .WithValueField(25, 5, out regularSequence[11], name: "12th conversion in regular sequence"); + + Registers.RegularSequence3.Define(this) + .WithValueField(0, 5, out regularSequence[0], name: "1st conversion in regular sequence") + .WithValueField(5, 5, out regularSequence[1], name: "2nd conversion in regular sequence") + .WithValueField(10, 5, out regularSequence[2], name: "3rd conversion in regular sequence") + .WithValueField(15, 5, out regularSequence[3], name: "4th conversion in regular sequence") + .WithValueField(20, 5, out regularSequence[4], name: "5th conversion in regular sequence") + .WithValueField(25, 5, out regularSequence[5], name: "6th conversion in regular sequence"); + + // Data register + Registers.RegularData.Define(this) + .WithValueField(0, 32, + valueProviderCallback: _ => + { + this.Log(LogLevel.Debug, "Reading ADC data {0}", adcData); + // Reading ADC_DR should clear EOC + endOfConversion.Value = false; + IRQ.Set(false); + return adcData; + }); + } + + private void EnableADC() + { + currentChannel = channels[regularSequence[currentChannelIdx].Value]; + } + + private void StartConversion() + { + if(adcOn.Value) + { + this.Log(LogLevel.Debug, "Starting conversion time={0}", + machine.ElapsedVirtualTime.TimeElapsed); + + // Enable timer, which will simulate conversion being performed. + samplingTimer.Enabled = true; + } + else + { + this.Log(LogLevel.Warning, "Trying to start conversion while ADC off"); + } + } + + private void OnConversionFinished() + { + this.Log(LogLevel.Debug, "OnConversionFinished: time={0} channel={1}", + machine.ElapsedVirtualTime.TimeElapsed, + currentChannelIdx); + + // Set data register and trigger DMA request + currentChannel.PrepareSample(); + adcData = currentChannel.GetSample(); + if(dmaEnabled.Value && dmaIssueRequest.Value) + { + // Issue DMA peripheral request, which when mapped to DMA + // controller will trigger a peripheral to memory transfer + DMARequest.Set(); + DMARequest.Unset(); + } + + var scanModeActive = scanMode.Value && currentChannelIdx < regularSequenceLen - 1; + var scanModeFinished = scanMode.Value && currentChannelIdx == regularSequenceLen - 1; + + // Signal EOC if EOCS set with scan mode enabled and finished or we finished scanning regular group + endOfConversion.Value = scanModeActive ? (endOfConversionSelect.Value || scanModeFinished) : true; + + // Iterate to next channel + currentChannelIdx = (currentChannelIdx + 1) % regularSequenceLen; + currentChannel = channels[regularSequence[currentChannelIdx].Value]; + + // Auto trigger next conversion if we're scanning or CONT bit set + samplingTimer.Enabled = scanModeActive || continuousConversion.Value; + + // Trigger EOC interrupt + if(endOfConversion.Value && eocInterruptEnable.Value) + { + this.Log(LogLevel.Debug, "OnConversionFinished: Set IRQ"); + IRQ.Set(true); + } + } + + // Control 1/2 fields + private IFlagRegisterField scanMode; + private IFlagRegisterField endOfConversion; + private IFlagRegisterField adcOn; + private IFlagRegisterField endOfConversionSelect; + private IFlagRegisterField eocInterruptEnable; + private IFlagRegisterField continuousConversion; + + private IFlagRegisterField dmaEnabled; + private IFlagRegisterField dmaIssueRequest; + + // Sampling timer. Provides time-based event for driving conversion of + // regular channel sequence. + private readonly LimitTimer samplingTimer; + + // Data sample to be returned from data register when read. + private uint adcData; + + // Regular sequence settings, i.e. the channels and order of channels + // for performing conversion + private uint regularSequenceLen; + private readonly IValueRegisterField[] regularSequence = new IValueRegisterField[19]; + + // Channel objects, for managing input test data + private uint currentChannelIdx; + private ADCChannel currentChannel; + private readonly ADCChannel[] channels; + + public const int NumberOfChannels = 19; + + private enum Registers + { + Status = 0x0, + Control1 = 0x4, + Control2 = 0x8, + SampleTime1 = 0x0C, + SampleTime2 = 0x10, + InjectedChannelDataOffset1 = 0x14, + InjectedChannelDataOffset2 = 0x18, + InjectedChannelDataOffset3 = 0x1C, + InjectedChannelDataOffset4 = 0x20, + WatchdogHigherThreshold = 0x24, + WatchdogLowerThreshold = 0x28, + RegularSequence1 = 0x2C, + RegularSequence2 = 0x30, + RegularSequence3 = 0x34, + InjectedSequence = 0x38, + InjectedData1 = 0x3C, + InjectedData2 = 0x40, + InjectedData3 = 0x44, + InjectedData4 = 0x48, + RegularData = 0x4C + } + } +} diff --git a/Renode/STM32_UART_Fix.cs b/Renode/STM32_UART_Fix.cs new file mode 100644 index 000000000..c0758c1a1 --- /dev/null +++ b/Renode/STM32_UART_Fix.cs @@ -0,0 +1,307 @@ +// +// Copyright (c) 2010-2023 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using Antmicro.Renode.Peripherals.Bus; +using System.Collections.Generic; +using Antmicro.Migrant; +using Antmicro.Migrant.Hooks; +using Antmicro.Renode.Core.Structure.Registers; + +namespace Antmicro.Renode.Peripherals.UART +{ + public class STM32_UART_Fix : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral + { + public STM32_UART_Fix(Machine machine, uint frequency = 8000000) : base(machine) + { + IRQ = new GPIO(); + ReceiveDmaRequest = new GPIO(); + registers = new DoubleWordRegisterCollection(this, BuildRegisterMap()); + this.frequency = frequency; + } + + public override void Reset() + { + base.Reset(); + registers.Reset(); + IRQ.Unset(); + ReceiveDmaRequest.Unset(); + } + + public uint ReadDoubleWord(long offset) + { + return registers.Read(offset); + } + + public void WriteDoubleWord(long offset, uint value) + { + registers.Write(offset, value); + } + + public ushort ReadWord(long offset) + { + return (ushort)registers.Read(offset); + } + + public void WriteWord(long offset, ushort value) + { + registers.Write(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte)registers.Read(offset); + } + + public void WriteByte(long offset, byte value) + { + registers.Write(offset, value); + } + + public override uint BaudRate + { + get + { + //OversamplingMode.By8 means we ignore the oldest bit of dividerFraction.Value + var fraction = oversamplingMode.Value == OversamplingMode.By16 ? dividerFraction.Value : dividerFraction.Value & 0b111; + + var divisor = 8 * (2 - (int)oversamplingMode.Value) * (dividerMantissa.Value + fraction / 16.0); + return divisor == 0 ? 0 : (uint)(frequency / divisor); + } + } + + public override Bits StopBits + { + get + { + switch(stopBits.Value) + { + case StopBitsValues.Half: + return Bits.Half; + case StopBitsValues.One: + return Bits.One; + case StopBitsValues.OneAndAHalf: + return Bits.OneAndAHalf; + case StopBitsValues.Two: + return Bits.Two; + default: + throw new ArgumentException("Invalid stop bits value"); + } + } + } + + public override Parity ParityBit => parityControlEnabled.Value ? + (paritySelection.Value == ParitySelection.Even ? + Parity.Even : + Parity.Odd) : + Parity.None; + + public BufferState BufferState + { + get + { + return bufferState; + } + + private set + { + if(bufferState == value) + { + return; + } + bufferState = value; + UpdateInterrupt(); + rdrNotEmpty.Value = (value != BufferState.Empty); + BufferStateChanged?.Invoke(value); + ReceiveDmaRequest.Set(receiveDmaEnabled.Value && rdrNotEmpty.Value); + } + } + + public event Action BufferStateChanged; + + public GPIO IRQ { get; } = new GPIO(); + public GPIO ReceiveDmaRequest { get; } + + public DoubleWordRegisterCollection registers{ get; } + + protected override void CharWritten() + { + BufferState = BufferState.Ready; + } + + protected override void QueueEmptied() + { + BufferState = BufferState.Empty; + } + + protected override bool IsReceiveEnabled => receiverEnabled.Value && usartEnabled.Value; + + private Dictionary BuildRegisterMap() + { + var registersMap = new Dictionary + { + {(long)Registers.Status, new DoubleWordRegister(this, resetValue: 0xC0) + .WithTaggedFlag("PE", 0) + .WithTaggedFlag("FE", 1) + .WithTaggedFlag("NF", 2) + .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => false, name: "ORE") // we assume no receive overruns + .WithTaggedFlag("IDLE", 4) + .WithFlag(5, out rdrNotEmpty, FieldMode.Read, valueProviderCallback: _ => (Count != 0), name: "RXNE") // as these two flags are WZTC, we cannot just calculate their results + .WithFlag(6, out transmissionComplete, FieldMode.Read, name: "TC") + .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "TXE") // we always assume "transmit data register empty" + .WithTaggedFlag("LBD", 8) + .WithTaggedFlag("CTS", 9) + .WithReservedBits(10, 22) + }, + {(long)Registers.Data, new DoubleWordRegister(this) + .WithValueField(0, 9, + valueProviderCallback: _ => HandleReceiveData(), + writeCallback: (_, value) => HandleTransmitData((uint)value), + name: "DR" + ) + }, + {(long)Registers.BaudRate, new DoubleWordRegister(this) + .WithValueField(0, 4, out dividerFraction, name: "DIV_Fraction") + .WithValueField(4, 12, out dividerMantissa, name: "DIV_Mantissa") + }, + {(long)Registers.Control1, new DoubleWordRegister(this) + .WithTaggedFlag("SBK", 0) + .WithTaggedFlag("RWU", 1) + .WithFlag(2, out receiverEnabled, name: "RE") + .WithFlag(3, out transmitterEnabled, name: "TE") + .WithTaggedFlag("IDLEIE", 4) + .WithFlag(5, out receiverNotEmptyInterruptEnabled, name: "RXNEIE") + .WithFlag(6, out transmissionCompleteInterruptEnabled, name: "TCIE") + .WithFlag(7, out transmitDataRegisterEmptyInterruptEnabled, name: "TXEIE") + .WithTaggedFlag("PEIE", 8) + .WithEnumField(9, 1, out paritySelection, name: "PS") + .WithFlag(10, out parityControlEnabled, name: "PCE") + .WithTaggedFlag("WAKE", 11) + .WithTaggedFlag("M", 12) + .WithFlag(13, out usartEnabled, name: "UE") + .WithReservedBits(14, 1) + .WithEnumField(15, 1, out oversamplingMode, name: "OVER8") + .WithReservedBits(16, 16) + .WithWriteCallback((_, __) => UpdateInterrupt()) + }, + {(long)Registers.Control2, new DoubleWordRegister(this) + .WithTag("ADD", 0, 4) + .WithReservedBits(5, 1) + .WithTaggedFlag("LBDIE", 6) + .WithReservedBits(7, 1) + .WithTaggedFlag("LBCL", 8) + .WithTaggedFlag("CPHA", 9) + .WithTaggedFlag("CPOL", 10) + .WithTaggedFlag("CLKEN", 11) + .WithEnumField(12, 2, out stopBits, name: "STOP") + .WithTaggedFlag("LINEN", 14) + .WithReservedBits(15, 17) + }, + {(long)Registers.Control3, new DoubleWordRegister(this) + .WithTaggedFlag("EIE", 0) + .WithTaggedFlag("IREN", 1) + .WithTaggedFlag("IRLP", 2) + .WithTaggedFlag("HDSEL", 3) + .WithTaggedFlag("NACK", 4) + .WithTaggedFlag("SCEN", 5) + .WithTaggedFlag("DMAR", 6) + .WithFlag(7, out receiveDmaEnabled, name: "DMAT") + .WithTaggedFlag("RTSE", 8) + .WithTaggedFlag("CTSE", 9) + .WithTaggedFlag("CTSIE", 10) + .WithTaggedFlag("ONEBIT", 11) + .WithReservedBits(12, 20) + } + }; + + return registersMap; + } + + private void HandleTransmitData(uint value) + { + if(transmitterEnabled.Value && usartEnabled.Value) + { + base.TransmitCharacter((byte)value); + transmissionComplete.Value = true; + UpdateInterrupt(); + } + else + { + this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring."); + } + } + + private uint HandleReceiveData() + { + if(!TryGetCharacter(out var result)) + { + this.Log(LogLevel.Warning, "No characters in queue."); + } + return result; + } + + private void UpdateInterrupt() + { + var transmitRegisterEmptyInterrupt = transmitDataRegisterEmptyInterruptEnabled.Value; // we assume that transmit register is always empty + var transmissionCompleteInterrupt = transmissionComplete.Value && transmissionCompleteInterruptEnabled.Value; + var receiverNotEmptyInterrupt = Count != 0 && receiverNotEmptyInterruptEnabled.Value; + + IRQ.Set(transmitRegisterEmptyInterrupt || transmissionCompleteInterrupt || receiverNotEmptyInterrupt); + } + + private IEnumRegisterField oversamplingMode; + private IEnumRegisterField stopBits; + private IFlagRegisterField usartEnabled; + private IFlagRegisterField parityControlEnabled; + private IEnumRegisterField paritySelection; + private IFlagRegisterField transmissionCompleteInterruptEnabled; + private IFlagRegisterField transmitDataRegisterEmptyInterruptEnabled; + private IFlagRegisterField receiverNotEmptyInterruptEnabled; + private IFlagRegisterField receiverEnabled; + private IFlagRegisterField transmitterEnabled; + private IFlagRegisterField rdrNotEmpty; + private IFlagRegisterField receiveDmaEnabled; + private IFlagRegisterField transmissionComplete; + private IValueRegisterField dividerMantissa; + private IValueRegisterField dividerFraction; + + private BufferState bufferState; + private readonly uint frequency; + + private enum OversamplingMode + { + By16 = 0, + By8 = 1 + } + + private enum StopBitsValues + { + One = 0, + Half = 1, + Two = 2, + OneAndAHalf = 3 + } + + private enum ParitySelection + { + Even = 0, + Odd = 1 + } + + private enum Registers : long + { + Status = 0x00, + Data = 0x04, + BaudRate = 0x08, + Control1 = 0x0C, + Control2 = 0x10, + Control3 = 0x14, + GuardTimeAndPrescaler = 0x18 + } + } +} diff --git a/Renode/startup.resc b/Renode/startup.resc new file mode 100644 index 000000000..c12200a79 --- /dev/null +++ b/Renode/startup.resc @@ -0,0 +1,51 @@ +$bin?=$ORIGIN/../Objects/controls-leader.elf +$platform=$ORIGIN/stm32f413.repl + +EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.DMA.STM32DMA" +include $ORIGIN/STM32DMA_Fix.cs + +EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.Analog.STM32_ADC" +include $ORIGIN/STM32_ADC_Fix.cs + +EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.UART.STM32_UART" +include $ORIGIN/STM32_UART_Fix.cs + +macro reset +""" + sysbus LoadELF $bin +""" + +macro show_uart_leader +""" + emulation CreateServerSocketTerminal $uart2_telnet "ldr-uart-con" false + connector Connect sysbus.usart2 ldr-uart-con +""" + +macro show_uart_display +""" + emulation CreateServerSocketTerminal $uart3_telnet "disp-uart-con" false + connector Connect sysbus.usart3 disp-uart-con +""" + +macro create_leader +""" + mach create "ctrl-leader" + mach set "ctrl-leader" + machine LoadPlatformDescription $platform + sysbus LoadELF $bin + logLevel 3 + runMacro $show_uart_leader + runMacro $show_uart_display + machine StartGdbServer 3333 true + connector Connect sysbus.can1 carCan + connector Connect sysbus.can3 motorCan +""" + +emulation CreateCANHub "carCan" +emulation CreateCANHub "motorCan" +emulation SetGlobalAdvanceImmediately true + +runMacro $create_leader + +mach set "ctrl-leader" +string Renode Simulator is now active \ No newline at end of file diff --git a/Simulator/stm32f413.repl b/Renode/stm32f413.repl similarity index 82% rename from Simulator/stm32f413.repl rename to Renode/stm32f413.repl index c16639e07..c6c50a7f0 100644 --- a/Simulator/stm32f413.repl +++ b/Renode/stm32f413.repl @@ -42,7 +42,7 @@ gpioPortA: GPIOPort.STM32_GPIOPort @ sysbus <0x40020000, +0x400> [0-15] -> exti@[0-15] spi5i2s5: SPI.STM32SPI @ sysbus 0x40015000 - -> nvic@85 + IRQ -> nvic@85 timer11: Timers.STM32_Timer @ sysbus <0x40014800, +0x400> initialLimit: 0xffff @@ -59,32 +59,42 @@ timer9: Timers.STM32_Timer @ sysbus <0x40014000, +0x400> frequency: 100000000 -> nvic@24 -exti: IRQControllers.EXTI @ sysbus 0x40013C00 +exti: IRQControllers.STM32F4_EXTI @ sysbus 0x40013C00 + numberOfOutputLines: 24 [0-9, 13] -> nvic@[6-10, 23, 40, 1, 41, 42, 3] + +nvicInput23: Miscellaneous.CombinedInput @ none + numberOfInputs: 5 + -> nvic@23 + +nvicInput40: Miscellaneous.CombinedInput @ none + numberOfInputs: 6 + -> nvic@40 syscfg: Miscellaneous.STM32_SYSCFG @ sysbus 0x40013800 [0-15] -> exti@[0-15] spi4i2s4: SPI.STM32SPI @ sysbus 0x40013400 - -> nvic@84 + IRQ -> nvic@84 spi1i2s1: SPI.STM32SPI @ sysbus 0x40013000 - -> nvic@35 + IRQ -> nvic@35 -adc: Analog.STM32_ADC @ sysbus 0x40012000 +adc: Analog.STM32_ADC_Fix @ sysbus 0x40012000 IRQ -> nvic@18 + DMARequest -> dma2@0 -uart10: UART.STM32_UART @ sysbus <0x40011C00, 0x40011FFF> - -> nvic@89 +uart10: UART.STM32_UART_Fix @ sysbus <0x40011C00, 0x40011FFF> + IRQ -> nvic@89 -uart9: UART.STM32_UART @ sysbus <0x40011800, 0x40011BFF> - -> nvic@88 +uart9: UART.STM32_UART_Fix @ sysbus <0x40011800, 0x40011BFF> + IRQ -> nvic@88 -usart6: UART.STM32_UART @ sysbus <0x40011400, +0x400> - -> nvic@71 +usart6: UART.STM32_UART_Fix @ sysbus <0x40011400, +0x400> + IRQ -> nvic@71 -usart1: UART.STM32_UART @ sysbus <0x40011000, +0x400> - -> nvic@37 +usart1: UART.STM32_UART_Fix @ sysbus <0x40011000, +0x400> + IRQ -> nvic@37 timer8: Timers.STM32_Timer @ sysbus <0x40010400, +0x400> initialLimit: 0xffff @@ -94,11 +104,11 @@ timer1: Timers.STM32_Timer @ sysbus <0x40010000, +0x400> initialLimit: 0xffff frequency: 100000000 -uart8: UART.STM32_UART @ sysbus <0x40007C00, 0x40007FFF> - -> nvic@83 +uart8: UART.STM32_UART_Fix @ sysbus <0x40007C00, 0x40007FFF> + IRQ -> nvic@83 -uart7: UART.STM32_UART @ sysbus <0x40007800, 0x40007BFF> - -> nvic@82 +uart7: UART.STM32_UART_Fix @ sysbus <0x40007800, 0x40007BFF> + IRQ -> nvic@82 can3: CAN.STMCAN @ sysbus <0x40006C00, 0x40006FFF> [0-3] -> nvic@[74-77] @@ -126,29 +136,29 @@ i2c1: I2C.STM32F4_I2C @ sysbus 0x40005400 EventInterrupt -> nvic@31 ErrorInterrupt -> nvic@32 -uart5: UART.STM32_UART @ sysbus <0x40005000, +0x400> - -> nvic@53 +uart5: UART.STM32_UART_Fix @ sysbus <0x40005000, +0x400> + IRQ -> nvic@53 -uart4: UART.STM32_UART @ sysbus <0x40004C00, +0x400> - -> nvic@52 +uart4: UART.STM32_UART_Fix @ sysbus <0x40004C00, +0x400> + IRQ -> nvic@52 -usart3: UART.STM32_UART @ sysbus <0x40004800, +0x400> - -> nvic@39 +usart3: UART.STM32_UART_Fix @ sysbus <0x40004800, +0x400> + IRQ -> nvic@39 -usart2: UART.STM32_UART @ sysbus <0x40004400, +0x400> - -> nvic@38 +usart2: UART.STM32_UART_Fix @ sysbus <0x40004400, +0x400> + IRQ -> nvic@38 i2s3ext: SPI.STM32SPI @ sysbus 0x40004000 spi3i2s3: SPI.STM32SPI @ sysbus 0x40003C00 - -> nvic@51 + IRQ -> nvic@51 spi2i2s2: SPI.STM32SPI @ sysbus 0x40003800 - -> nvic@36 + IRQ -> nvic@36 i2s2ext: SPI.STM32SPI @ sysbus 0x40003400 -iwdg: Timers.STM32F4_IndependentWatchdog @ sysbus 0x40003000 +iwdg: Timers.STM32_IndependentWatchdog @ sysbus 0x40003000 frequency: 32000 // windowOption: false // defaultPrescaler: 0x4 diff --git a/Scripts/load_env_vars.sh b/Scripts/load_env_vars.sh new file mode 100755 index 000000000..9b088cf01 --- /dev/null +++ b/Scripts/load_env_vars.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +export CONTROLS_REPO=$(git -C "$(dirname "$BASH_SOURCE")" rev-parse --show-toplevel) +export RENODE_VERSION=1.14.0 +export RENODE_UART2_TELNET=49152 +export RENODE_UART3_TELNET=49153 \ No newline at end of file diff --git a/Scripts/start_renode.sh b/Scripts/start_renode.sh new file mode 100755 index 000000000..30a5f6382 --- /dev/null +++ b/Scripts/start_renode.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if [[ -z "${RENODE_UART2_TELNET}" ]] || [[ -z "${RENODE_UART3_TELNET}" ]]; then + echo "Please add your load_env_vars.sh script to your .bashrc in order to load the environment variables." ; exit 1 +fi + +(renode -v | grep -q "Renode, version $RENODE_VERSION") && (echo "Starting Renode." && \ + renode --disable-xwt --console \ + -e "\$uart2_telnet=${RENODE_UART2_TELNET}; \ + \$uart3_telnet=${RENODE_UART3_TELNET}; \ + include @Renode/startup.resc") || echo "Please install version $RENODE_VERSION of Renode simulator." \ No newline at end of file diff --git a/Simulator/bpsSim.elf b/Simulator/bpsSim.elf deleted file mode 100755 index c5120030b..000000000 Binary files a/Simulator/bpsSim.elf and /dev/null differ diff --git a/Simulator/startup.resc b/Simulator/startup.resc deleted file mode 100644 index 8a5ce1437..000000000 --- a/Simulator/startup.resc +++ /dev/null @@ -1,93 +0,0 @@ -$bin?=@Objects/controls-leader.elf -$bps_bin?=@Objects/car-sim.elf -$motor_bin?=@Objects/motor-sim.elf -$platform=@Simulator/stm32f413.repl - -macro reset -""" - sysbus LoadELF $bin -""" - -macro show_uart_leader -""" - emulation CreateServerSocketTerminal 49152 "ldr-uart-con" false - connector Connect sysbus.usart2 ldr-uart-con -""" - -macro show_uart_display -""" - emulation CreateServerSocketTerminal 49153 "disp-uart-con" false - connector Connect sysbus.usart3 disp-uart-con -""" - -macro show_uart_motor -""" - emulation CreateServerSocketTerminal 49154 "motor-uart-con" false - connector Connect sysbus.usart2 motor-uart-con -""" - -macro show_uart_bps -""" - emulation CreateServerSocketTerminal 49155 "bps-uart-con" false - connector Connect sysbus.usart2 bps-uart-con -""" - -set periphWriteHook """ -print "START WRITE HOOK" -print 'Periph: %s'%self -print 'Value: %s'%hex(value) -print 'Offset: %s'%hex(offset) -print "\n" -""" - -set periphReadHook """ -print "START READ HOOK" -print 'Periph: %s'%self -print 'Value: %s'%hex(value) -print 'Offset: %s'%hex(offset) -print "\np" -""" - -set can1_WriteHook """ -if(hex(offset) == "0x180L"): - print('MSG ID: %s'%hex(value>>21)) -elif(hex(offset) == "0x188L"): - print('Data Lower Half: %s'%hex(value)) -elif(hex(offset) == "0x18cL"): - print('Data Upper Half: %s'%hex(value)) - print("\n") -""" - -emulation CreateCANHub "carCan" -emulation CreateCANHub "motorCan" - -mach create "ctrl-leader" -mach set "ctrl-leader" -machine LoadPlatformDescription $platform -sysbus LoadELF $bin -logLevel 3 -runMacro $show_uart_leader -runMacro $show_uart_display -machine StartGdbServer 3333 -connector Connect sysbus.can1 carCan -connector Connect sysbus.can3 motorCan - -mach create "bps-sim" -mach set "bps-sim" -machine LoadPlatformDescription $platform -sysbus LoadELF $bps_bin -logLevel 3 -runMacro $show_uart_bps -machine StartGdbServer 3334 -connector Connect sysbus.can1 carCan - -mach create "motor-sim" -mach set "motor-sim" -machine LoadPlatformDescription $platform -sysbus LoadELF $motor_bin -logLevel 3 -runMacro $show_uart_motor -machine StartGdbServer 3335 -connector Connect sysbus.can3 motorCan - -mach set "ctrl-leader" diff --git a/Simulator/stm32f412.repl b/Simulator/stm32f412.repl deleted file mode 100644 index f63d1eb10..000000000 --- a/Simulator/stm32f412.repl +++ /dev/null @@ -1,227 +0,0 @@ -cpu: CPU.CortexM @ sysbus - cpuType: "cortex-m4f" - nvic: nvic - -nvic: IRQControllers.NVIC @ sysbus 0xE000E000 - -> cpu@0 - -rng: Miscellaneous.STM32F4_RNG @ sysbus 0x50060800 - -> nvic@80 - -dma2: DMA.STM32DMA @ sysbus 0x40026400 - [0-7] -> nvic@[56-60,68-70] - -dma1: DMA.STM32DMA @ sysbus 0x40026000 - [0-7] -> nvic@[11-17,47] - -rcc: Miscellaneous.STM32F4_RCC @ sysbus 0x40023800 - rtcPeripheral: rtc - -gpioPortH: GPIOPort.STM32_GPIOPort @ sysbus <0x40021C00, +0x400> - [0-15] -> exti@[0-15] - -gpioPortG: GPIOPort.STM32_GPIOPort @ sysbus <0x40021800, +0x400> - [0-15] -> exti@[0-15] - -gpioPortF: GPIOPort.STM32_GPIOPort @ sysbus <0x40021400, +0x400> - [0-15] -> exti@[0-15] - -gpioPortE: GPIOPort.STM32_GPIOPort @ sysbus <0x40021000, +0x400> - [0-15] -> exti@[0-15] - -gpioPortD: GPIOPort.STM32_GPIOPort @ sysbus <0x40020C00, +0x400> - [0-15] -> exti@[0-15] - -gpioPortC: GPIOPort.STM32_GPIOPort @ sysbus <0x40020800, +0x400> - [0-15] -> exti@[0-15] - -gpioPortB: GPIOPort.STM32_GPIOPort @ sysbus <0x40020400, +0x400> - [0-15] -> exti@[0-15] - -gpioPortA: GPIOPort.STM32_GPIOPort @ sysbus <0x40020000, +0x400> - [0-15] -> exti@[0-15] - -spi5i2s5: SPI.STM32SPI @ sysbus 0x40015000 - -> nvic@85 - -timer11: Timers.STM32_Timer @ sysbus <0x40014800, +0x400> - initialLimit: 0xffff - frequency: 100000000 - -> nvic@26 - -timer10: Timers.STM32_Timer @ sysbus <0x40014400, +0x400> - initialLimit: 0xffff - frequency: 100000000 - -> nvic@25 - -timer9: Timers.STM32_Timer @ sysbus <0x40014000, +0x400> - initialLimit: 0xffff - frequency: 100000000 - -> nvic@24 - -exti: IRQControllers.EXTI @ sysbus 0x40013C00 - [0-9, 13] -> nvic@[6-10, 23, 40, 1, 41, 42, 3] - -syscfg: Miscellaneous.STM32_SYSCFG @ sysbus 0x40013800 - [0-15] -> exti@[0-15] - -spi4i2s4: SPI.STM32SPI @ sysbus 0x40013400 - -> nvic@84 - -spi1i2s1: SPI.STM32SPI @ sysbus 0x40013000 - -> nvic@35 - -adc: Analog.STM32_ADC @ sysbus 0x40012000 - IRQ -> nvic@18 - -usart6: UART.STM32_UART @ sysbus <0x40011400, +0x400> - -> nvic@71 - -usart1: UART.STM32_UART @ sysbus <0x40011000, +0x400> - -> nvic@37 - -timer8: Timers.STM32_Timer @ sysbus <0x40010400, +0x400> - initialLimit: 0xffff - frequency: 100000000 - -timer1: Timers.STM32_Timer @ sysbus <0x40010000, +0x400> - initialLimit: 0xffff - frequency: 100000000 - -can2: CAN.STMCAN @ sysbus <0x40006800, +0x400> - [0-3] -> nvic@[63-66] - master: can1 - -can1: CAN.STMCAN @ sysbus <0x40006400, +0x400> - [0-3] -> nvic@[19-22] - -i2cfmp1: I2C.STM32F7_I2C @ sysbus 0x40006000 - EventInterrupt -> nvic@95 - ErrorInterrupt -> nvic@96 - -i2c3: I2C.STM32F4_I2C @ sysbus 0x40005C00 - EventInterrupt -> nvic@72 - ErrorInterrupt -> nvic@73 - -i2c2: I2C.STM32F4_I2C @ sysbus 0x40005800 - EventInterrupt -> nvic@33 - ErrorInterrupt -> nvic@34 - -i2c1: I2C.STM32F4_I2C @ sysbus 0x40005400 - EventInterrupt -> nvic@31 - ErrorInterrupt -> nvic@32 - -usart3: UART.STM32_UART @ sysbus <0x40004800, +0x400> - -> nvic@39 - -usart2: UART.STM32_UART @ sysbus <0x40004400, +0x400> - -> nvic@38 - -i2s3ext: SPI.STM32SPI @ sysbus 0x40004000 - -spi3i2s3: SPI.STM32SPI @ sysbus 0x40003C00 - -> nvic@51 - -spi2i2s2: SPI.STM32SPI @ sysbus 0x40003800 - -> nvic@36 - -i2s2ext: SPI.STM32SPI @ sysbus 0x40003400 - -iwdg: Timers.STM32F4_IndependentWatchdog @ sysbus 0x40003000 - frequency: 32000 - -rtc: Timers.STM32F4_RTC @ sysbus 0x40002800 - AlarmIRQ -> exti@17 - -timer14: Timers.STM32_Timer @ sysbus <0x40002000, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@45 - -timer13: Timers.STM32_Timer @ sysbus <0x40001C00, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@44 - -timer12: Timers.STM32_Timer @ sysbus <0x40001800, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@43 - -timer7: Timers.STM32_Timer @ sysbus <0x40001400, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@55 - -timer6: Timers.STM32_Timer @ sysbus <0x40001000, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@54 - -timer5: Timers.STM32_Timer @ sysbus <0x40000C00, +0x400> - initialLimit: 0xffffffff - frequency: 50000000 - -> nvic@50 - -timer4: Timers.STM32_Timer @ sysbus <0x40000800, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@30 - -timer3: Timers.STM32_Timer @ sysbus <0x40000400, +0x400> - initialLimit: 0xffff - frequency: 50000000 - -> nvic@29 - -timer2: Timers.STM32_Timer @ sysbus <0x40000000, +0x400> - initialLimit: 0xffffffff - frequency: 50000000 - -> nvic@28 - -sram: Memory.MappedMemory @ { -// sysbus 0x0; // BOOT 11 - sysbus 0x20000000 - } - size: 0x40000 - -// The original size is 0x210, but due to limitations of the MappedMemory -// size has to be aligned to the guest page size. -otp: Memory.MappedMemory @ sysbus 0x1FFF7800 - size: 0x400 - -ram: Memory.MappedMemory @ { -// sysbus 0x0; // BOOT 01 - sysbus 0x1FFF0000 - } - size: 0x7800 - - -// For aliasing `flash` is split into `flash0` and `flash1` to alias only 0x40000 bytes, -// for other boot options this could be simplified to a single `flash` peripheral. -// flash: Memory.MappedMemory @ sysbus 0x8000000 -// size: 0x100000 - -flash0: Memory.MappedMemory @ { - sysbus 0x0; // BOOT x0 - sysbus 0x8000000 - } - size: 0x40000 - -flash1: Memory.MappedMemory @ sysbus 0x8040000 - size: 0xc0000 - -sysbus: - init: - Tag <0x1FFFC0000, 0x1FFFC000F> "Option_bytes" - Tag <0xA0001000, 0xA0001FFF> "QuadSPI_control_register" - Tag <0xA0000000, 0xA0000FFF> "FSMC_control_register" - Tag <0x90000000, 0x9FFFFFFF> "QuadSPI" - Tag <0x60000000, 0x6FFFFFFF> "FSMC" - Tag <0x50000000, 0x5003FFFF> "USB_OTG_FS" - Tag <0x40023C00, 0x40023FFF> "Flash_interface_register" - Tag <0x40023C00, 0x40023FFF> "CRC" - Tag <0x40016000, 0x400163FF> "DFSDM1" - Tag <0x40012C00, 0x40012FFF> "SDIO" - Tag <0x40007000, 0x400073FF> "PWR" - Tag <0x40003000, 0x400033FF> "IWDG" - Tag <0x40002C00, 0x40002FFF> "WWDG" diff --git a/Tests/Test_BSP_CAN.c b/Tests/Test_BSP_CAN.c old mode 100755 new mode 100644 diff --git a/Tests/Test_HelloWorld.c b/Tests/Test_HelloWorld.c new file mode 100644 index 000000000..220bce2b3 --- /dev/null +++ b/Tests/Test_HelloWorld.c @@ -0,0 +1,12 @@ +#include "common.h" +#include "config.h" +#include + +int main(void){ + BSP_UART_Init(UART_2); + printf("Hello World\n"); + + while(1){} + + return 0; +} \ No newline at end of file diff --git a/install.sh b/install.sh deleted file mode 100755 index d5b3eae03..000000000 --- a/install.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -RED='\033[0;31m' -NC='\033[0m' -distro=$(cat /etc/issue) - -if [ "${distro:0:4}" = "Arch" ]; then -#special case for arch linux -sudo pacman -Sy arm-none-eabi-newlib stlink openocd --noconfirm -else -# Compile code for the microcontroller -echo -e "${RED}\nInstall Arm Toolchain...\n==================================\n${NC}" -wget "https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi.tar.xz?rev=95edb5e17b9d43f28c74ce824f9c6f10&hash=176C4D884DBABB657ADC2AC886C8C095409547C4" --show-progress && -mv "arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi.tar.xz?rev=95edb5e17b9d43f28c74ce824f9c6f10&hash=176C4D884DBABB657ADC2AC886C8C095409547C4" arm-none-eabi.tar.xz && -echo "Extracting tar, this may take a few minutes" && -tar -xf arm-none-eabi.tar.xz && -rm arm-none-eabi.tar.xz && -sudo mv arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi /usr/share/ -sudo ln -s /usr/share/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc /usr/bin/arm-none-eabi-gcc -sudo ln -s /usr/share/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g++ /usr/bin/arm-none-eabi-g++ -sudo ln -s /usr/share/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-objcopy /usr/bin/arm-none-eabi-objcopy -sudo ln -s /usr/share/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-size /usr/bin/arm-none-eabi-size - - - -# Debug code on the microcontroller -echo -e "${RED}\nInstall openocd...\n==================================\n${NC}" -sudo apt-get -y install openocd - -# GDB -echo -e "${RED}\nInstall gdb-multiarch...\n==================================\n${NC}" -sudo apt-get -y install gdb-multiarch - -# Run make command and compile projects -echo -e "${RED}\nInstall build-essential...\n==================================\n${NC}" -sudo apt-get -y install build-essential -fi -# Make sure that necessary OS submodules are initialized -if [ -d ".git" ]; then - echo -e "${RED}\nUpdate and initialize submodules...\n==================================\n${NC}" - git submodule update --init --recursive -fi - -echo -e "${RED}\nFinished! Jolly good!\n${NC}" diff --git a/simulate b/simulate deleted file mode 100644 index 835bd9a5a..000000000 --- a/simulate +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -#make sure to run make first and startup XLaunch before running this script - -function simulate() -{ - cd "$(dirname "$0")" - - if [[ $(uname -a | grep Microsoft) ]]; then - echo "Running a new WSL window/shell..." - cmd.exe /c start cmd.exe /c "mode con: cols=103 lines=33 && wsl.exe ./controls-simulator.out" & - cmd.exe /c start cmd.exe /c "mode con: cols=103 lines=33 && wsl.exe python3 BSP/Simulator/Hardware/simulate.py" & - else - echo "Running gnome-terminal..." - gnome-terminal --working-directory="$(pwd)" --geometry=103x33 -- ./controls-simulator.out - gnome-terminal --working-directory="$(pwd)" --geometry=103x33 -- python3 BSP/Simulator/Hardware/simulate.py - fi - - - -simulate