Compare commits

..

24 Commits

Author SHA1 Message Date
6f0009cfbb Fixed critical ring buffer underflow bug 2026-06-03 19:11:50 +02:00
f8b73ea1bc Broken spark implementation 2026-06-03 17:45:48 +02:00
Pierre Barbier
1e8d3b766f Coding guidelines documentation 2026-06-03 14:47:39 +02:00
de4b471790 Started docs 2026-06-03 14:22:13 +02:00
f23f852b6c Merge branch 'dev' of git.h3cx.dev:Exergie/NeoECU-Firmware into dev 2026-06-03 14:21:29 +02:00
16fd59535e Update config for CH3 output compare 2026-06-03 14:19:55 +02:00
Pierre Barbier
1771904eac Added Injection time and a phase macro 2026-06-03 13:52:01 +02:00
Pierre Barbier
31bdeeaf50 delat macros and crank miss filter 2026-06-03 12:02:17 +02:00
bacb144369 Fixed CRANK and CAM macros 2026-06-03 11:51:50 +02:00
Pierre Barbier
c5d5e89461 fixed a little problem in cam 2026-06-03 11:49:04 +02:00
5fed925b7f Updated crank to use macros 2026-06-03 11:48:40 +02:00
Pierre Barbier
e75f21ccf6 things 2026-06-03 11:44:27 +02:00
Pierre Barbier
0909c180e8 added cam double trigger and pragma once in GS 2026-06-03 11:35:21 +02:00
Pierre Barbier
cfe15f2612 Added Crank and Cam macros 2026-06-03 11:20:26 +02:00
e346c67e00 Ring buffer fixes and spark time compute 2026-06-03 11:18:44 +02:00
42e64b673c Initial sync implementation
Implemented system sync with crank and cam state and simple error
handling
2026-06-03 10:56:28 +02:00
21f0b5a3ea Added ring buffer revert 2026-06-03 08:45:10 +02:00
22c732be02 Refactor handler to external
Moved task handler functions to external functions, signatures are in
tasks.h, each function has its own .c file in Src/tasks
2026-06-02 20:11:07 +02:00
8d1debd69a Added print on interrupt via task flag 2026-06-02 19:46:05 +02:00
0e99868078 Added SEGGER RTT files 2026-06-02 19:45:49 +02:00
Pierre Barbier
ce2b76e6c0 added a crank_state to general_state 2026-06-02 18:06:32 +02:00
Pierre Barbier
bca9d8816c consistant naming for global_state and implemented 2026-06-02 17:54:15 +02:00
Pierre Barbier
eba2bb6f99 Fixed ring_buffer's linking problems 2026-06-02 17:48:52 +02:00
e7e436affa Updated ring buffer
Updated ring buffer to match use case, one write head with negative read
index
2026-06-02 17:29:46 +02:00
19 changed files with 4117 additions and 194 deletions

View File

@@ -59,6 +59,11 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add sources to executable
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
Core/Src/ring_buffer.c
Core/Src/SEGGER_RTT.c
Core/Src/SEGGER_RTT_printf.c
Core/Src/tasks/crank.c
Core/Src/tasks/cam.c
)
# Link directories setup

View File

@@ -0,0 +1,520 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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 SEGGER Microcontroller 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. *
* *
**********************************************************************
* *
* RTT version: 8.56a *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT.h
Purpose : Implementation of SEGGER real-time transfer which allows
real-time communication on targets which support debugger
memory accesses while the CPU is running.
Revision: $Rev: 25842 $
----------------------------------------------------------------------
*/
#ifndef SEGGER_RTT_H
#define SEGGER_RTT_H
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, defaults
*
**********************************************************************
*/
#ifndef RTT_USE_ASM
//
// Some cores support out-of-order memory accesses (reordering of memory accesses in the core)
// For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers.
// Needed for:
// Cortex-M7 (ARMv7-M)
// Cortex-M23 (ARM-v8M)
// Cortex-M33 (ARM-v8M)
// Cortex-A/R (ARM-v7A/R)
//
// We do not explicitly check for "Embedded Studio" as the compiler in use determines what we support.
// You can use an external toolchain like IAR inside ES. So there is no point in checking for "Embedded Studio"
//
#if (defined __CROSSWORKS_ARM) // Rowley Crossworks
#define _CC_HAS_RTT_ASM_SUPPORT 1
#if (defined __ARM_ARCH_7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined(__ARM_ARCH_8_1M_MAIN__)) // Cortex-M85
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#elif (defined __ARMCC_VERSION)
//
// ARM compiler
// ARM compiler V6.0 and later is clang based.
// Our ASM part is compatible to clang.
//
#if (__ARMCC_VERSION >= 6000000)
#define _CC_HAS_RTT_ASM_SUPPORT 1
#else
#define _CC_HAS_RTT_ASM_SUPPORT 0
#endif
#if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1
#define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture
#elif (defined __ARM_ARCH_7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif \
((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) || \
((defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__))
//
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
//
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#elif ((defined __GNUC__) || (defined __clang__))
//
// GCC / Clang
//
#define _CC_HAS_RTT_ASM_SUPPORT 1
// ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__
#if (defined __ARM_ARCH_7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here...
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif \
(defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__) || \
(defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__)
//
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
//
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#elif ((defined __IASMARM__) || (defined __ICCARM__))
//
// IAR assembler/compiler
//
#define _CC_HAS_RTT_ASM_SUPPORT 1
#if (__VER__ < 6300000)
#define VOLATILE
#else
#define VOLATILE volatile
#endif
#if (defined __ARM7M__) // Needed for old versions that do not know the define yet
#if (__CORE__ == __ARM7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#endif
#endif
#if (defined __ARM7EM__)
#if (__CORE__ == __ARM7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm VOLATILE ("DMB");
#endif
#endif
#if (defined __ARM8M_BASELINE__)
#if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm VOLATILE ("DMB");
#endif
#endif
#if (defined __ARM8M_MAINLINE__)
#if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm VOLATILE ("DMB");
#endif
#endif
#if (defined __ARM8EM_MAINLINE__)
#if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-???
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm VOLATILE ("DMB");
#endif
#endif
#if\
((defined __ARM7A__) && (__CORE__ == __ARM7A__)) || \
((defined __ARM7R__) && (__CORE__ == __ARM7R__)) || \
((defined __ARM8A__) && (__CORE__ == __ARM8A__)) || \
((defined __ARM8R__) && (__CORE__ == __ARM8R__))
//
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
//
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm VOLATILE ("DMB");
#endif
#else
//
// Other compilers
//
#define _CC_HAS_RTT_ASM_SUPPORT 0
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
//
// If IDE and core support the ASM version, enable ASM version by default
//
#ifndef _CORE_HAS_RTT_ASM_SUPPORT
#define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores
#endif
#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT)
#define RTT_USE_ASM (1)
#else
#define RTT_USE_ASM (0)
#endif
#endif
#ifndef _CORE_NEEDS_DMB
#define _CORE_NEEDS_DMB 0
#endif
#ifndef RTT__DMB
#if _CORE_NEEDS_DMB
#error "Don't know how to place inline assembly for DMB"
#else
#define RTT__DMB()
#endif
#endif
#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE
#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a good default here
#endif
#ifndef SEGGER_RTT_UNCACHED_OFF
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE
#error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
#else
#define SEGGER_RTT_UNCACHED_OFF (0)
#endif
#endif
#if RTT_USE_ASM
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE
#error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
#endif
#endif
#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
//
// Determine how much we must pad the control block to make it a multiple of a cache line in size
// Assuming: U8 = 1B
// U16 = 2B
// U32 = 4B
// U8/U16/U32* = 4B
//
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache
#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * SEGGER_RTT_CPU_CACHE_LINE_SIZE)
#else
#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes)
#endif
#define SEGGER_RTT__CB_SIZE (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24))
#define SEGGER_RTT__CB_PADDING (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE)
/*********************************************************************
*
* Types
*
**********************************************************************
*/
//
// Description for a circular buffer (also called "ring buffer")
// which is used as up-buffer (T->H)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
unsigned WrOff; // Position of next item to be written by either target.
volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode.
} SEGGER_RTT_BUFFER_UP;
//
// Description for a circular buffer (also called "ring buffer")
// which is used as down-buffer (H->T)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
unsigned RdOff; // Position of next item to be read by target (down-buffer).
unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode.
} SEGGER_RTT_BUFFER_DOWN;
//
// RTT control block which describes the number of buffers available
// as well as the configuration for each buffer
//
//
typedef struct {
char acID[16]; // Initialized to "SEGGER RTT"
int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
#if SEGGER_RTT__CB_PADDING
unsigned char aDummy[SEGGER_RTT__CB_PADDING];
#endif
} SEGGER_RTT_CB;
/*********************************************************************
*
* Global data
*
**********************************************************************
*/
extern SEGGER_RTT_CB _SEGGER_RTT;
/*********************************************************************
*
* RTT API functions
*
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_GetKey (void);
unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
int SEGGER_RTT_HasKey (void);
unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex);
void SEGGER_RTT_Init (void);
unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_WaitKey (void);
unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex);
unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex);
//
// Function macro for performance optimization
//
#define SEGGER_RTT_HASDATA(n) (((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff)
#if RTT_USE_ASM
#define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock
#endif
/*********************************************************************
*
* RTT transfer functions to send RTT data via other channels.
*
**********************************************************************
*/
unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
#define SEGGER_RTT_HASDATA_UP(n) (((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly
/*********************************************************************
*
* RTT "Terminal" API functions
*
**********************************************************************
*/
int SEGGER_RTT_SetTerminal (unsigned char TerminalId);
int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s);
/*********************************************************************
*
* RTT printf functions (require SEGGER_RTT_printf.c)
*
**********************************************************************
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
#ifdef __cplusplus
}
#endif
#endif // ifndef(SEGGER_RTT_ASM)
//
// For some environments, NULL may not be defined until certain headers are included
//
#ifndef NULL
#define NULL ((void*)0)
#endif
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
//
// Operating modes. Define behavior if buffer is full (not enough space for entire message)
//
#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)
#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.
#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.
#define SEGGER_RTT_MODE_MASK (3)
//
// Control sequences, based on ANSI.
// Can be used to control color, and clear the screen
//
#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
#define RTT_CTRL_BG_RED "\x1B[24;41m"
#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,440 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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 SEGGER Microcontroller 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. *
* *
**********************************************************************
* *
* RTT version: 8.56a *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Conf.h
Purpose : Implementation of SEGGER real-time transfer (RTT) which
allows real-time communication on targets which support
debugger memory accesses while the CPU is running.
Revision: $Rev: 24316 $
*/
#ifndef SEGGER_RTT_CONF_H
#define SEGGER_RTT_CONF_H
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h>
#endif
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
//
// Take in and set to correct values for Cortex-A systems with CPU cache
//
//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in bytes) in the current system
//#define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // Address alias where RTT CB and buffers can be accessed uncached
//
// Most common case:
// Up-channel 0: RTT
// Up-channel 1: SystemView
//
#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3)
#endif
//
// Most common case:
// Down-channel 0: RTT
// Down-channel 1: SystemView
//
#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3)
#endif
#ifndef BUFFER_SIZE_UP
#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
#endif
#ifndef BUFFER_SIZE_DOWN
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
#endif
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
#endif
#ifndef SEGGER_RTT_MODE_DEFAULT
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
#endif
/*********************************************************************
*
* RTT memcpy configuration
*
* memcpy() is good for large amounts of data,
* but the overhead is big for small amounts, which are usually stored via RTT.
* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.
*
* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.
* This is may be required with memory access restrictions,
* such as on Cortex-A devices with MMU.
*/
#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP
#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
#endif
//
// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets
//
//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))
// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes))
//#endif
//
// Target is not allowed to perform other RTT operations while string still has not been stored completely.
// Otherwise we would probably end up with a mixed string in the buffer.
// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
//
// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
// (Higher priority = lower priority number)
// Default value for embOS: 128u
// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
// or define SEGGER_RTT_LOCK() to completely disable interrupts.
//
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
#endif
/*********************************************************************
*
* RTT lock configuration for SEGGER Embedded Studio,
* Rowley CrossStudio and GCC
*/
#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32))
#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
__asm volatile ("mrs %0, primask \n\t" \
"movs r1, #1 \n\t" \
"msr primask, r1 \n\t" \
: "=r" (_SEGGER_RTT__LockState) \
: \
: "r1", "cc" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
: \
: "r" (_SEGGER_RTT__LockState) \
: \
); \
}
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
__asm volatile ("mrs %0, basepri \n\t" \
"mov r1, %1 \n\t" \
"msr basepri, r1 \n\t" \
: "=r" (_SEGGER_RTT__LockState) \
: "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
: "r1", "cc" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
: \
: "r" (_SEGGER_RTT__LockState) \
: \
); \
}
#elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__))
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
__asm volatile ("mrs r1, CPSR \n\t" \
"mov %0, r1 \n\t" \
"orr r1, r1, #0xC0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: "=r" (_SEGGER_RTT__LockState) \
: \
: "r1", "cc" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
"mrs r1, CPSR \n\t" \
"bic r1, r1, #0xC0 \n\t" \
"and r0, r0, #0xC0 \n\t" \
"orr r1, r1, r0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: \
: "r" (_SEGGER_RTT__LockState) \
: "r0", "r1", "cc" \
); \
}
#elif defined(__riscv) || defined(__riscv_xlen)
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
__asm volatile ("csrr %0, mstatus \n\t" \
"csrci mstatus, 8 \n\t" \
"andi %0, %0, 8 \n\t" \
: "=r" (_SEGGER_RTT__LockState) \
: \
: \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \
"or %0, %0, a1 \n\t" \
"csrs mstatus, %0 \n\t" \
: \
: "r" (_SEGGER_RTT__LockState) \
: "a1" \
); \
}
#else
#define SEGGER_RTT_LOCK()
#define SEGGER_RTT_UNLOCK()
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR EWARM
*/
#ifdef __ICCARM__
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \
(defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \
}
#elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \
(defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = __get_BASEPRI(); \
__set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() __set_BASEPRI(_SEGGER_RTT__LockState); \
}
#elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__)) || \
(defined (__ARM7R__) && (__CORE__ == __ARM7R__))
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
__asm volatile ("mrs r1, CPSR \n\t" \
"mov %0, r1 \n\t" \
"orr r1, r1, #0xC0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: "=r" (_SEGGER_RTT__LockState) \
: \
: "r1", "cc" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
"mrs r1, CPSR \n\t" \
"bic r1, r1, #0xC0 \n\t" \
"and r0, r0, #0xC0 \n\t" \
"orr r1, r1, r0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: \
: "r" (_SEGGER_RTT__LockState) \
: "r0", "r1", "cc" \
); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RX
*/
#ifdef __ICCRX__
#define SEGGER_RTT_LOCK() { \
unsigned long _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RL78
*/
#ifdef __ICCRL78__
#define SEGGER_RTT_LOCK() { \
__istate_t _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for KEIL ARM
*/
#ifdef __CC_ARM
#if (defined __TARGET_ARCH_6S_M)
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
register unsigned char _SEGGER_RTT__PRIMASK __asm( "primask"); \
_SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \
_SEGGER_RTT__PRIMASK = 1u; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \
__schedule_barrier(); \
}
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
register unsigned char BASEPRI __asm( "basepri"); \
_SEGGER_RTT__LockState = BASEPRI; \
BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() BASEPRI = _SEGGER_RTT__LockState; \
__schedule_barrier(); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for TI ARM
*/
#ifdef __TI_ARM__
#if defined (__TI_ARM_V6M0__)
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \
}
#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() _set_interrupt_priority(_SEGGER_RTT__LockState); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for CCRX
*/
#ifdef __RX
#include <machine.h>
#define SEGGER_RTT_LOCK() { \
unsigned long _SEGGER_RTT__LockState; \
_SEGGER_RTT__LockState = get_psw() & 0x010000; \
clrpsw_i();
#define SEGGER_RTT_UNLOCK() set_psw(get_psw() | _SEGGER_RTT__LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for embOS Simulation on Windows
* (Can also be used for generic RTT locking with embOS)
*/
#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS)
void OS_SIM_EnterCriticalSection(void);
void OS_SIM_LeaveCriticalSection(void);
#define SEGGER_RTT_LOCK() { \
OS_SIM_EnterCriticalSection();
#define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \
}
#endif
/*********************************************************************
*
* RTT lock configuration fallback
*/
#ifndef SEGGER_RTT_LOCK
#define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts)
#endif
#ifndef SEGGER_RTT_UNLOCK
#define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
#endif
/*********************************************************************
*
* If SEGGER_RTT_SECTION is defined but SEGGER_RTT_BUFFER_SECTION
* is not, use the same section for SEGGER_RTT_BUFFER_SECTION.
*/
#ifndef SEGGER_RTT_BUFFER_SECTION
#if defined(SEGGER_RTT_SECTION)
#define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION
#endif
#endif
#endif
/*************************** End of file ****************************/

View File

@@ -1,16 +0,0 @@
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <ring_buffer.h>
typedef enum {
SYNC_OK,
SYNC_PENDING,
SYNC_NOT_OK
} sync_state;
typedef struct {
sync_state sync;
ring_buffer_t crank_RB;
ring_buffer_t cam_RB;
} global_state_t;

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <ring_buffer.h>
#include <stdbool.h>
#include <stdint.h>
#define MAX_CAM_MISS 2
#define SPARK_ADVANCE 40
#define INJECTION_PHASE 0
typedef enum { SYNC_OK = 0, SYNC_PENDING = 1, SYNC_NOT_OK = 2 } sync_state_t;
typedef enum {
CYCLE_COMBUSTION = 0,
CYCLE_EXHAUST = 1,
CYCLE_INTAKE = 2,
CYCLE_COMPRESSION = 3,
CYCLE_UNKNOWN = 4
} crank_state_t;
typedef enum { CAM_IDLE = 0, CAM_TRIGD = 1 } cam_state_t;
typedef enum {
SPARK_IDLE = 0,
SPARK_CHARGING = 1,
SPARK_NONE = 2
} spark_state_t;
typedef struct {
crank_state_t crank_state;
cam_state_t cam_state;
uint8_t cam_miss_ctr;
sync_state_t sync_state;
ring_buffer_t crank_RB;
ring_buffer_t cam_RB;
spark_state_t next_spark_state;
spark_state_t current_spark_state;
} global_state_t;

View File

@@ -0,0 +1,15 @@
// Copyright (C) 2026 Hector van der Aa <hector@h3cx.dev>
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "global_state.h"
#ifdef DEBUG
#include "SEGGER_RTT.h"
#define DEBUG_LOG(fmt, ...) SEGGER_RTT_printf(0, fmt "\n", ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...) \
do { \
} while (0)
#endif
#define CRANK(num) ringBufferRead(&state_g.crank_RB, num)
#define CAM(num) ringBufferRead(&state_g.cam_RB, num)

View File

@@ -1,21 +1,21 @@
/* 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) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
@@ -31,6 +31,7 @@ extern "C" {
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "global_state.h"
/* USER CODE END Includes */
@@ -41,7 +42,8 @@ extern "C" {
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
extern volatile global_state_t state_g;
extern TIM_HandleTypeDef htim2;
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
@@ -49,6 +51,8 @@ extern "C" {
/* USER CODE END EM */
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
@@ -59,10 +63,10 @@ void Error_Handler(void);
/* Private defines -----------------------------------------------------------*/
#define LED_RED_Pin GPIO_PIN_12
#define LED_RED_GPIO_Port GPIOI
#define TIM2_CRANK_Pin GPIO_PIN_0
#define TIM2_CRANK_GPIO_Port GPIOA
#define TIM2_CAM_Pin GPIO_PIN_1
#define TIM2_CAM_GPIO_Port GPIOA
#define TIM2_CRANK_Pin GPIO_PIN_0
#define TIM2_CRANK_GPIO_Port GPIOA
/* USER CODE BEGIN Private defines */

View File

@@ -1,14 +1,15 @@
// Copyright (C) 2026 Hector van der Aa <hector@h3cx.dev>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <stdint.h>
typedef struct ring_buffer_t {
uint32_t buffer[256];
uint8_t w_head;
uint8_t r_head;
} ring_buffer_t;
inline void ringBufferPush(ring_buffer_t *rb, uint32_t value);
inline void ringBufferPush(volatile ring_buffer_t *rb, uint32_t value);
inline int ringBufferPop(ring_buffer_t *rb, uint32_t *output);
inline uint32_t ringBufferRead(volatile ring_buffer_t *rb, uint8_t neg_idx);
inline void ringBufferRevert(volatile ring_buffer_t *rb, uint8_t val);

View File

@@ -0,0 +1,7 @@
// Copyright (C) 2026 Hector van der Aa <hector@h3cx.dev>
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
void crankHandler(void *argument);
void camHandler(void *argument);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,522 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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 SEGGER Microcontroller 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. *
* *
**********************************************************************
* *
* RTT version: 8.56a *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_printf.c
Purpose : Replacement for printf to write formatted data via RTT
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
#endif
#include <stdlib.h>
#include <stdarg.h>
#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
#define FORMAT_FLAG_PAD_ZERO (1u << 1)
#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
#define FORMAT_FLAG_ALTERNATE (1u << 3)
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
char* pBuffer;
unsigned BufferSize;
unsigned Cnt;
int ReturnValue;
unsigned RTTBufferIndex;
} SEGGER_RTT_PRINTF_DESC;
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _StoreChar
*/
static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
unsigned Cnt;
Cnt = p->Cnt;
if ((Cnt + 1u) <= p->BufferSize) {
*(p->pBuffer + Cnt) = c;
p->Cnt = Cnt + 1u;
p->ReturnValue++;
}
//
// Write part of string, when the buffer is full
//
if (p->Cnt == p->BufferSize) {
if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
p->ReturnValue = -1;
} else {
p->Cnt = 0u;
}
}
}
/*********************************************************************
*
* _PrintUnsigned
*/
static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
unsigned Div;
unsigned Digit;
unsigned Number;
unsigned Width;
char c;
Number = v;
Digit = 1u;
//
// Get actual field width
//
Width = 1u;
while (Number >= Base) {
Number = (Number / Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
//
// Print leading chars if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
if (FieldWidth != 0u) {
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
c = '0';
} else {
c = ' ';
}
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, c);
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Compute Digit.
// Loop until Digit has the value of the highest digit required.
// Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
//
while (1) {
if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
NumDigits--;
} else {
Div = v / Digit;
if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done
break;
}
}
Digit *= Base;
}
//
// Output digits
//
do {
Div = v / Digit;
v -= Div * Digit;
_StoreChar(pBufferDesc, _aV2C[Div]);
if (pBufferDesc->ReturnValue < 0) {
break;
}
Digit /= Base;
} while (Digit);
//
// Print trailing spaces if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
}
}
/*********************************************************************
*
* _PrintInt
*/
static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
unsigned Width;
int Number;
Number = (v < 0) ? -v : v;
//
// Get actual field width
//
Width = 1u;
while (Number >= (int)Base) {
Number = (Number / (int)Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
FieldWidth--;
}
//
// Print leading spaces if necessary
//
if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
//
// Print sign if necessary
//
if (pBufferDesc->ReturnValue >= 0) {
if (v < 0) {
v = -v;
_StoreChar(pBufferDesc, '-');
} else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
_StoreChar(pBufferDesc, '+');
} else {
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print leading zeros if necessary
//
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, '0');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print number without sign
//
_PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
}
}
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* SEGGER_RTT_vprintf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string
* pParamList Pointer to the list of arguments for the format string
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*/
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
char c;
SEGGER_RTT_PRINTF_DESC BufferDesc;
int v;
unsigned char PrecisionSet;
unsigned Precision;
unsigned FormatFlags;
unsigned FieldWidth;
char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
BufferDesc.pBuffer = acBuffer;
BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
BufferDesc.Cnt = 0u;
BufferDesc.RTTBufferIndex = BufferIndex;
BufferDesc.ReturnValue = 0;
do {
c = *sFormat;
sFormat++;
if (c == 0u) {
break;
}
if (c == '%') {
//
// Filter out flags
//
FormatFlags = 0u;
v = 1;
do {
c = *sFormat;
switch (c) {
case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
default: v = 0; break;
}
} while (v);
//
// filter out field with
//
FieldWidth = 0u;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
} while (1);
//
// Filter out precision (number of digits to display)
//
PrecisionSet = 0;
Precision = 0u;
c = *sFormat;
if (c == '.') {
sFormat++;
if (*sFormat == '*') {
sFormat++;
PrecisionSet = 1;
Precision = va_arg(*pParamList, int);
} else {
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
PrecisionSet = 1;
sFormat++;
Precision = Precision * 10u + ((unsigned)c - '0');
} while (1);
}
}
//
// Filter out length modifier
//
c = *sFormat;
do {
if ((c == 'l') || (c == 'h')) {
sFormat++;
c = *sFormat;
} else {
break;
}
} while (1);
//
// Handle specifiers
//
switch (c) {
case 'c': {
char c0;
v = va_arg(*pParamList, int);
c0 = (char)v;
_StoreChar(&BufferDesc, c0);
break;
}
case 'd':
v = va_arg(*pParamList, int);
_PrintInt(&BufferDesc, v, 10u, Precision, FieldWidth, FormatFlags);
break;
case 'u':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 10u, Precision, FieldWidth, FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, Precision, FieldWidth, FormatFlags);
break;
case 's':
{
const char * s = va_arg(*pParamList, const char *);
if (s == NULL) {
s = "(NULL)"; // Print (NULL) instead of crashing or breaking, as it is more informative to the user.
PrecisionSet = 0; // Make sure (NULL) is printed, even when precision was set.
}
do {
c = *s;
s++;
if (c == '\0') {
break;
}
if ((PrecisionSet != 0) && (Precision == 0)) {
break;
}
_StoreChar(&BufferDesc, c);
Precision--;
} while (BufferDesc.ReturnValue >= 0);
}
break;
case 'p':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
break;
case '%':
_StoreChar(&BufferDesc, '%');
break;
default:
break;
}
sFormat++;
} else {
_StoreChar(&BufferDesc, c);
}
} while (BufferDesc.ReturnValue >= 0);
if (BufferDesc.ReturnValue > 0) {
//
// Write remaining data, if any
//
if (BufferDesc.Cnt != 0u) {
SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
}
BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
}
return BufferDesc.ReturnValue;
}
/*********************************************************************
*
* SEGGER_RTT_printf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string, followed by the arguments for conversion
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*
* Notes
* (1) Conversion specifications have following syntax:
* %[flags][FieldWidth][.Precision]ConversionSpecifier
* (2) Supported flags:
* -: Left justify within the field width
* +: Always print sign extension for signed conversions
* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
* Supported conversion specifiers:
* c: Print the argument as one char
* d: Print the argument as a signed integer
* u: Print the argument as an unsigned integer
* x: Print the argument as an hexadecimal integer
* s: Print the string pointed to by the argument
* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
int r;
va_list ParamList;
va_start(ParamList, sFormat);
r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
va_end(ParamList);
return r;
}
/*************************** End of file ****************************/

View File

@@ -8,11 +8,19 @@
#include "main.h"
#include "FreeRTOS.h"
#include "cmsis_os2.h"
#include "stm32h7xx_hal_tim.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "global_state.h"
#include "macros.h"
#include "ring_buffer.h"
#include "stm32h7xx_hal_tim.h"
#include "tasks.h"
#include <assert.h>
#include <stdbool.h>
#ifdef DEBUG
#include "SEGGER_RTT.h"
#endif
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -50,36 +58,36 @@ TIM_HandleTypeDef htim2;
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t)osPriorityNormal,
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for crankTask */
osThreadId_t crankTaskHandle;
uint32_t crankTaskBuffer[128];
uint32_t crankTaskBuffer[ 128 ];
osStaticThreadDef_t crankTaskControlBlock;
const osThreadAttr_t crankTask_attributes = {
.name = "crankTask",
.cb_mem = &crankTaskControlBlock,
.cb_size = sizeof(crankTaskControlBlock),
.stack_mem = &crankTaskBuffer[0],
.stack_size = sizeof(crankTaskBuffer),
.priority = (osPriority_t)osPriorityRealtime7,
.name = "crankTask",
.cb_mem = &crankTaskControlBlock,
.cb_size = sizeof(crankTaskControlBlock),
.stack_mem = &crankTaskBuffer[0],
.stack_size = sizeof(crankTaskBuffer),
.priority = (osPriority_t) osPriorityRealtime7,
};
/* Definitions for camTask */
osThreadId_t camTaskHandle;
uint32_t camTaskBuffer[128];
uint32_t camTaskBuffer[ 128 ];
osStaticThreadDef_t camTaskControlBlock;
const osThreadAttr_t camTask_attributes = {
.name = "camTask",
.cb_mem = &camTaskControlBlock,
.cb_size = sizeof(camTaskControlBlock),
.stack_mem = &camTaskBuffer[0],
.stack_size = sizeof(camTaskBuffer),
.priority = (osPriority_t)osPriorityRealtime7,
.name = "camTask",
.cb_mem = &camTaskControlBlock,
.cb_size = sizeof(camTaskControlBlock),
.stack_mem = &camTaskBuffer[0],
.stack_size = sizeof(camTaskBuffer),
.priority = (osPriority_t) osPriorityRealtime7,
};
/* USER CODE BEGIN PV */
volatile global_state_t state_g = {0};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@@ -88,8 +96,8 @@ static void MPU_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
void StartDefaultTask(void *argument);
void crankHandler(void *argument);
void camHandler(void *argument);
extern void crankHandler(void *argument);
extern void camHandler(void *argument);
/* USER CODE BEGIN PFP */
@@ -97,17 +105,38 @@ void camHandler(void *argument);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3) {
if (state_g.next_spark_state == SPARK_IDLE &&
state_g.current_spark_state == SPARK_CHARGING) {
DEBUG_LOG("Releasing spark");
} else if (state_g.next_spark_state == SPARK_CHARGING &&
state_g.current_spark_state == SPARK_IDLE) {
DEBUG_LOG("Charging spark");
osThreadFlagsSet(crankTaskHandle, 0x02);
}
if (state_g.next_spark_state != SPARK_NONE) {
state_g.current_spark_state = state_g.next_spark_state;
state_g.next_spark_state = SPARK_NONE;
}
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
switch (htim->Channel) {
// HAL_TIM_ACTIVE_CHANNEL_2 is the channel used for cam interupts
case HAL_TIM_ACTIVE_CHANNEL_2:
// TODO push timestamp to the cam ring buffer
ringBufferPush(&state_g.cam_RB,
HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2));
osThreadFlagsSet(camTaskHandle, 0x01);
break;
// HAL_TIM_ACTIVE_CHANNEL_1 is the channel used for crank interupts
case HAL_TIM_ACTIVE_CHANNEL_1:
// TODO push timestamp to the crank ring buffer
ringBufferPush(&state_g.crank_RB,
HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1));
osThreadFlagsSet(crankTaskHandle, 0x01);
break;
default:
@@ -119,10 +148,11 @@ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void) {
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
@@ -131,7 +161,7 @@ int main(void) {
#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)
int32_t timeout;
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_0 */
/* USER CODE END Boot_Mode_Sequence_0 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
@@ -146,15 +176,19 @@ int main(void) {
Error_Handler();
}
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_1 */
/* USER CODE END Boot_Mode_Sequence_1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick.
*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
state_g.sync_state = SYNC_NOT_OK;
state_g.crank_state = CYCLE_UNKNOWN;
state_g.cam_state = CAM_IDLE;
state_g.cam_miss_ctr = 0;
state_g.next_spark_state = SPARK_NONE;
state_g.current_spark_state = SPARK_IDLE;
/* USER CODE END Init */
/* Configure the system clock */
@@ -177,7 +211,7 @@ int main(void) {
Error_Handler();
}
#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */
/* USER CODE END Boot_Mode_Sequence_2 */
/* USER CODE END Boot_Mode_Sequence_2 */
/* USER CODE BEGIN SysInit */
@@ -188,6 +222,12 @@ int main(void) {
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
#ifdef DEBUG
void SEGGER_RTT_Init(void);
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0,
SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
#endif
/* USER CODE END 2 */
/* Init scheduler */
@@ -211,8 +251,7 @@ int main(void) {
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle =
osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* creation of crankTask */
crankTaskHandle = osThreadNew(crankHandler, NULL, &crankTask_attributes);
@@ -244,27 +283,27 @@ int main(void) {
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void) {
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {
}
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
@@ -277,15 +316,16 @@ void SystemClock_Config(void) {
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 |
RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
@@ -294,17 +334,19 @@ void SystemClock_Config(void) {
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void) {
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
@@ -313,6 +355,7 @@ static void MX_TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
@@ -323,42 +366,66 @@ static void MX_TIM2_Init(void) {
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim2) != HAL_OK) {
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 10;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) {
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) {
sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void) {
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
@@ -394,59 +461,27 @@ static void MX_GPIO_Init(void) {
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument) {
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for (;;) {
osDelay(1);
osDelay(1000);
}
/* USER CODE END 5 */
}
/* USER CODE BEGIN Header_crankHandler */
/**
* @brief Function implementing the crankTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_crankHandler */
void crankHandler(void *argument) {
/* USER CODE BEGIN crankHandler */
/* Infinite loop */
for (;;) {
osThreadFlagsWait(0x01, osFlagsWaitAny, osWaitForever);
// TODO Handle the call
}
/* USER CODE END crankHandler */
}
/* MPU Configuration */
/* USER CODE BEGIN Header_camHandler */
/**
* @brief Function implementing the camTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_camHandler */
void camHandler(void *argument) {
/* USER CODE BEGIN camHandler */
/* Infinite loop */
for (;;) {
osThreadFlagsWait(0x01, osFlagsWaitAny, osWaitForever);
// TODO Handle the call
}
/* USER CODE END camHandler */
}
/* MPU Configuration */
void MPU_Config(void) {
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x0;
@@ -462,13 +497,15 @@ void MPU_Config(void) {
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void) {
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
@@ -478,13 +515,14 @@ void Error_Handler(void) {
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line) {
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line
number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file,

View File

@@ -5,24 +5,20 @@
#include <assert.h>
#include <ring_buffer.h>
#include <stdbool.h>
#include <stdint.h>
inline void ringBufferPush(ring_buffer_t *rb, uint32_t value) {
void ringBufferPush(volatile ring_buffer_t *rb, uint32_t value) {
rb->buffer[rb->w_head] = value;
rb->w_head++;
if (rb->w_head == rb->r_head) {
// if write head catches up to read head, crash program as consumer task
// should keep up with write head
assert(false);
}
return;
}
inline int ringBufferPop(ring_buffer_t *rb, uint32_t *output) {
if (rb->w_head == rb->r_head) {
// if read head is at write head, buffer is empty so nothing to pop
return 1;
}
*output = rb->buffer[rb->r_head];
rb->r_head++;
return 0;
uint32_t ringBufferRead(volatile ring_buffer_t *rb, uint8_t neg_idx) {
uint8_t idx = (uint8_t)(rb->w_head - 1u - neg_idx);
return rb->buffer[idx];
}
void ringBufferRevert(volatile ring_buffer_t *rb, uint8_t val) {
rb->w_head -= val;
return;
}

View File

@@ -56,7 +56,9 @@
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
@@ -96,10 +98,10 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM2 GPIO Configuration
PA1 ------> TIM2_CH2
PA0 ------> TIM2_CH1
PA1_C ------> TIM2_CH2
*/
GPIO_InitStruct.Pin = TIM2_CRANK_Pin|TIM2_CAM_Pin;
GPIO_InitStruct.Pin = TIM2_CAM_Pin|TIM2_CRANK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
@@ -117,6 +119,32 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspPostInit 0 */
/* USER CODE END TIM2_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM2 GPIO Configuration
PA2 ------> TIM2_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM2_MspPostInit 1 */
/* USER CODE END TIM2_MspPostInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
@@ -134,10 +162,11 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
__HAL_RCC_TIM2_CLK_DISABLE();
/**TIM2 GPIO Configuration
PA2 ------> TIM2_CH3
PA1 ------> TIM2_CH2
PA0 ------> TIM2_CH1
PA1_C ------> TIM2_CH2
*/
HAL_GPIO_DeInit(GPIOA, TIM2_CRANK_Pin|TIM2_CAM_Pin);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|TIM2_CAM_Pin|TIM2_CRANK_Pin);
/* TIM2 interrupt DeInit */
HAL_NVIC_DisableIRQ(TIM2_IRQn);

View File

@@ -0,0 +1,44 @@
// Copyright (C) 2026 Hector van der Aa <hector@h3cx.dev>
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "cmsis_os2.h"
#include "global_state.h"
#include "macros.h"
#include "main.h"
#include "ring_buffer.h"
#include "tasks.h"
void camHandler(void *argument) {
for (;;) {
osThreadFlagsWait(0x01, osFlagsWaitAny, osWaitForever);
DEBUG_LOG("Cam pulse detected at: %lu\n\r",
ringBufferRead(&state_g.cam_RB, 0));
// FILTERS
// if (CAM_TRIGD) {
// ringBufferRevert(&state_g.cam_RB,1);
// return;
// }
state_g.cam_state = CAM_TRIGD;
state_g.cam_miss_ctr = 0;
switch (state_g.sync_state) {
case SYNC_NOT_OK: {
state_g.sync_state = SYNC_PENDING;
DEBUG_LOG("Sync state updated to pending\n\r");
break;
}
case SYNC_PENDING: {
if (state_g.crank_state == CYCLE_COMPRESSION) {
state_g.sync_state = SYNC_OK;
DEBUG_LOG("Sync state updated to OK\n\r");
}
break;
}
default:
break;
}
}
}

View File

@@ -0,0 +1,117 @@
// Copyright (C) 2026 Hector van der Aa <hector@h3cx.dev>
// Copyright (C) 2026 Pierre Barbier <pierrebarbier741@gmail.com>
// Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "cmsis_os2.h"
#include "global_state.h"
#include "macros.h"
#include "main.h"
#include "ring_buffer.h"
#include "stm32h747xx.h"
#include "stm32h7xx.h"
#include "stm32h7xx_hal_tim.h"
#include "tasks.h"
#include <stdint.h>
static inline void TIM2_CH3_SetOCMode(uint32_t oc_mode) {
MODIFY_REG(TIM2->CCMR2, TIM_CCMR2_OC3M | TIM_CCMR2_OC3M_3, oc_mode);
}
void crankHandler(void *argument) {
for (;;) {
osThreadFlagsWait(0x01, osFlagsWaitAny, osWaitForever);
DEBUG_LOG("Crank pulse detected at: %lu\n\r",
ringBufferRead(&state_g.crank_RB, 0));
// FILTER
if (state_g.sync_state == SYNC_OK) {
uint32_t d1a = CRANK(0) - CRANK(1);
uint32_t d1b = CRANK(1) - CRANK(2);
int32_t delta_percentage =
((int64_t)d1a - (int64_t)d1b) * 100 / (int64_t)d1b;
DEBUG_LOG("%ld\n\r", delta_percentage);
if (delta_percentage > 40 || delta_percentage < -40) {
// state_g.sync_state = SYNC_NOT_OK;
// state_g.crank_state = CYCLE_UNKNOWN;
// ringBufferRevert(&state_g.crank_RB, 1);
state_g.crank_RB.w_head -= 1;
continue;
}
}
// INCREMENT SWITCH
switch (state_g.crank_state) {
case CYCLE_COMPRESSION: {
if (state_g.cam_state != CAM_TRIGD) {
DEBUG_LOG("Cam miss detected, sync dynamite incoming\n\r");
state_g.cam_miss_ctr++;
if (state_g.cam_miss_ctr > MAX_CAM_MISS) {
state_g.sync_state = SYNC_NOT_OK;
state_g.crank_state = CYCLE_UNKNOWN;
break;
}
}
state_g.crank_state = CYCLE_COMBUSTION;
DEBUG_LOG("Crank state incremented\n\r");
state_g.cam_state = CAM_IDLE;
break;
}
case CYCLE_COMBUSTION:
case CYCLE_EXHAUST:
case CYCLE_INTAKE: {
if (state_g.cam_state == CAM_TRIGD) {
state_g.sync_state = SYNC_NOT_OK;
state_g.crank_state = CYCLE_UNKNOWN;
state_g.cam_state = CAM_IDLE;
break;
}
state_g.crank_state++;
DEBUG_LOG("Crank state incremented\n\r");
break;
}
case CYCLE_UNKNOWN: {
if (state_g.sync_state == SYNC_PENDING &&
state_g.cam_state == CAM_TRIGD) {
state_g.crank_state = CYCLE_COMBUSTION;
state_g.cam_state = CAM_IDLE;
}
break;
}
}
// SPARK SCHEDULE
if (state_g.sync_state == SYNC_OK) {
switch (state_g.crank_state) {
case CYCLE_COMPRESSION: {
DEBUG_LOG("Spark schedule reached, congrats\n\r");
uint32_t d1a = CRANK(0) - CRANK(1);
// TODO: Map interpolation rather than SPARK_ADVANCE CONSTANT
uint32_t d_spark = d1a * (45 - SPARK_ADVANCE) / 180;
uint32_t t_spark = CRANK(0) + d_spark;
// TODO: schedule spark
if (state_g.current_spark_state != SPARK_CHARGING) {
uint32_t force_charge_time = __HAL_TIM_GET_COUNTER(&htim2) + 2000;
// TIM2_CH3_SetOCMode(TIM_OCMODE_ACTIVE);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, force_charge_time);
state_g.next_spark_state = SPARK_CHARGING;
osThreadFlagsWait(0x02, osFlagsWaitAny, osWaitForever);
}
DEBUG_LOG("Spark scheduled for: %lu , current time: %lu\n\r", t_spark,
__HAL_TIM_GET_COUNTER(&htim2));
// TIM2_CH3_SetOCMode(TIM_OCMODE_INACTIVE);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark);
state_g.next_spark_state = SPARK_IDLE;
break;
}
case CYCLE_EXHAUST: {
uint32_t t_injection =
CRANK(0) + (45 + INJECTION_PHASE) * (CRANK(4) - CRANK(0)) / 720;
// TODO: Schedule injection
break;
}
default:
break;
}
}
}
}

View File

@@ -9,7 +9,7 @@ CortexM7.IPs=CORTEX_M7\:I,FATFS_M7\:I,FREERTOS_M7\:I,IWDG1\:I,OPENAMP_M7\:I,PDM2
CortexM7.Pins=PI12
FREERTOS_M7.FootprintOK=true
FREERTOS_M7.IPParameters=Tasks01,configENABLE_FPU,FootprintOK
FREERTOS_M7.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;crankTask,55,128,crankHandler,Default,NULL,Static,crankTaskBuffer,crankTaskControlBlock;camTask,55,128,camHandler,Default,NULL,Static,camTaskBuffer,camTaskControlBlock
FREERTOS_M7.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;crankTask,55,128,crankHandler,As external,NULL,Static,crankTaskBuffer,crankTaskControlBlock;camTask,55,128,camHandler,As external,NULL,Static,camTaskBuffer,camTaskControlBlock
FREERTOS_M7.configENABLE_FPU=1
File.Version=6
GPIO.groupedBy=Group By Peripherals
@@ -33,18 +33,19 @@ Mcu.Name=STM32H747XIHx
Mcu.Package=TFBGA240
Mcu.Pin0=PA14 (JTCK/SWCLK)
Mcu.Pin1=PC15-OSC32_OUT (OSC32_OUT)
Mcu.Pin10=VP_SYS_VS_Systick
Mcu.Pin11=VP_SYS_M4_VS_Systick
Mcu.Pin12=VP_TIM2_VS_ClockSourceINT
Mcu.Pin10=VP_FREERTOS_M7_VS_CMSIS_V2
Mcu.Pin11=VP_SYS_VS_Systick
Mcu.Pin12=VP_SYS_M4_VS_Systick
Mcu.Pin13=VP_TIM2_VS_ClockSourceINT
Mcu.Pin2=PC14-OSC32_IN (OSC32_IN)
Mcu.Pin3=PA13 (JTMS/SWDIO)
Mcu.Pin4=PI12
Mcu.Pin5=PH1-OSC_OUT (PH1)
Mcu.Pin6=PH0-OSC_IN (PH0)
Mcu.Pin7=PA0
Mcu.Pin8=PA1_C
Mcu.Pin9=VP_FREERTOS_M7_VS_CMSIS_V2
Mcu.PinsNb=13
Mcu.Pin7=PA2
Mcu.Pin8=PA1
Mcu.Pin9=PA0
Mcu.PinsNb=14
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32H747XIHx
@@ -81,6 +82,11 @@ PA0.GPIO_Label=TIM2_CRANK
PA0.Locked=true
PA0.PinAttribute=CortexM7
PA0.Signal=S_TIM2_CH1_ETR
PA1.GPIOParameters=GPIO_Label,PinAttribute
PA1.GPIO_Label=TIM2_CAM
PA1.Locked=true
PA1.PinAttribute=CortexM7
PA1.Signal=S_TIM2_CH2
PA13\ (JTMS/SWDIO).GPIOParameters=PinAttribute
PA13\ (JTMS/SWDIO).Locked=true
PA13\ (JTMS/SWDIO).PinAttribute=CortexM7
@@ -89,11 +95,11 @@ PA14\ (JTCK/SWCLK).GPIOParameters=PinAttribute
PA14\ (JTCK/SWCLK).Locked=true
PA14\ (JTCK/SWCLK).PinAttribute=CortexM7
PA14\ (JTCK/SWCLK).Signal=DEBUG_JTCK-SWCLK
PA1_C.GPIOParameters=GPIO_Label,PinAttribute
PA1_C.GPIO_Label=TIM2_CAM
PA1_C.Locked=true
PA1_C.PinAttribute=CortexM7
PA1_C.Signal=S_TIM2_CH2
PA2.GPIOParameters=GPIO_Speed,PinAttribute
PA2.GPIO_Speed=GPIO_SPEED_FREQ_LOW
PA2.Locked=true
PA2.PinAttribute=CortexM7
PA2.Signal=S_TIM2_CH3
PC14-OSC32_IN\ (OSC32_IN).GPIOParameters=PinAttribute
PC14-OSC32_IN\ (OSC32_IN).Locked=true
PC14-OSC32_IN\ (OSC32_IN).Mode=LSE-External-Oscillator
@@ -245,11 +251,18 @@ SH.S_TIM2_CH1_ETR.0=TIM2_CH1,Input_Capture1_from_TI1
SH.S_TIM2_CH1_ETR.ConfNb=1
SH.S_TIM2_CH2.0=TIM2_CH2,Input_Capture2_from_TI2
SH.S_TIM2_CH2.ConfNb=1
SH.S_TIM2_CH3.0=TIM2_CH3,Output Compare3 CH3
SH.S_TIM2_CH3.ConfNb=1
SYS.userName=SYS_M7
TIM2.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1
TIM2.Channel-Input_Capture2_from_TI2=TIM_CHANNEL_2
TIM2.Channel-Output\ Compare3\ CH3=TIM_CHANNEL_3
TIM2.ClockDivision=TIM_CLOCKDIVISION_DIV4
TIM2.IPParameters=ClockDivision,Prescaler,Channel-Input_Capture1_from_TI1,Channel-Input_Capture2_from_TI2
TIM2.ICFilter_CH1=10
TIM2.ICFilter_CH2=10
TIM2.ICPolarity_CH1=TIM_INPUTCHANNELPOLARITY_FALLING
TIM2.IPParameters=ClockDivision,Prescaler,Channel-Input_Capture1_from_TI1,ICPolarity_CH1,Channel-Input_Capture2_from_TI2,ICFilter_CH2,ICFilter_CH1,Channel-Output Compare3 CH3,OCMode_3
TIM2.OCMode_3=TIM_OCMODE_TOGGLE
TIM2.Prescaler=0
VP_FREERTOS_M7_VS_CMSIS_V2.Mode=CMSIS_V2
VP_FREERTOS_M7_VS_CMSIS_V2.Signal=FREERTOS_M7_VS_CMSIS_V2
@@ -260,3 +273,4 @@ VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM2_VS_ClockSourceINT.Mode=Internal
VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
board=custom
rtos.0.ip=FREERTOS_M7

34
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,34 @@
# NeoECU Firmware Architecture
## AMP
NeoECU features an AMP (Asymmetric Multi Processing) architecture making use of both the `CM7` and `CM4` core of the STM32H747 MCU powering NeoECU
### CM7
The Cortex M7 is in charge of initial boot and more importantly all of the engine control. The core uses the following software stack:
- STM32_HAL
- FreeRTOS
- CMSISv2
This fairly low-level software stack, paired with strict coding rules, allows for stable and deterministic engine control. The key coding rules are:
- No heap allocation
- Pointer indirection limited to one level
Further coding rules, guidelines and conventions can be found in CODING.md
### CM4
The Cortex M4 handles all of the telemetry, and other vehicle functions. It will be build around ZephyrRTOS to allow for a higher level of abstraction and a complete I/O stack out of the box. The code written for this core will not follow the same rules as for the CM7 as anything run on the CM4 should be non critical to core engine function.
## Engine Control
As mentioned previously, all core engine control is handled on the Cortex M7, this is to isolate critical engine control from heavier telemetry operations that are non critical to core engine function.
### Input Signals
The engine provides two key input signals:
- Crank pulse, triggered every 180 deg
- Cam pulse, triggered every 720 deg and slightly dephased
These are both registered using a hardware interrupt using `TIM2` as a low jitter time source.
These signals can have missing pulses or extra triggers which need to be accounted for.
### Time Base
`TIM2` is the main timebase used to control the engine, it provides 4 channels that are used as follows:
- CH_1: Crank input compare
- CH_2: Cam input compare
- CH_3: Undefined
- CH_4: Undefined

20
docs/CODING.md Normal file
View File

@@ -0,0 +1,20 @@
# NeoECU Firmware Coding Guidelines
## Naming Conventions
Functions : camelCase
Variables : python_case
Constants : UPPER_CASE
Macros : UPPER_CASE
Types : python_case_t
## Performance Standard
Don't use heap at all if possible avoid mallocs at all cost.
Don't make heavy computation in ISR delegate everything to a task that you'll wake.
Don't copy big chunks of memory, use pointers if you need to read a buffer, even if simply passing the buffer as a parameter compiles it will have huge overhead.
## Readability Standard
Avoid more than one layer of pointer indirection if possible.
Don't use void* they are unclear and make mistakes more likely.
Avoid magic numbers and indexes, use macros and constants to define them clearly.
Define all macros in macros.h and all global variables and constants in glocal_state.h.
Use one c file per feature, avoid big monoliths that become hard to jump around.