Skip to content

Commit

Permalink
Refactoring & smaller pulse train descriptor.
Browse files Browse the repository at this point in the history
  • Loading branch information
Onwrikbaar committed Jan 10, 2025
1 parent 6f70bc4 commit 4135404
Show file tree
Hide file tree
Showing 11 changed files with 1,668 additions and 1,612 deletions.
1 change: 1 addition & 0 deletions firmware/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ PROJ_COMMON_SRC += \
$(PROJ_DIR_SRC)/sequencer.c \
$(PROJ_DIR_SRC)/pattern_iter.c \
$(PROJ_DIR_SRC)/pulse_train.c \
$(PROJ_DIR_SRC)/burst.c \
$(PROJ_DIR_SRC)/datalink.c \
$(PROJ_DIR_SRC)/debug_cli.c \
$(PROJ_DIR_SRC)/attributes.c \
Expand Down
3,062 changes: 1,535 additions & 1,527 deletions firmware/build/neodk_g071.hex

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion firmware/inc/bsp_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ int BSP_closeSerialPort(int fd);
// Pulse generation related functions.
uint16_t BSP_setPrimaryVoltage_mV(uint16_t V_prim_mV);
void BSP_primaryVoltageEnable(bool must_be_on);
bool BSP_startBurst(Burst const *);
bool BSP_startBurst(Burst const *, Deltas const *);

// Debugging stuff.
void BSP_triggerADC(void);
Expand Down
24 changes: 17 additions & 7 deletions firmware/inc/burst.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,31 @@
#ifndef INC_BURST_H_
#define INC_BURST_H_

#include <stdbool.h>
#include <stdint.h>

#define MIN_PULSE_WIDTH_¼_µs 6
#define MAX_PULSE_WIDTH_¼_µs 800

#define MIN_PULSE_PACE_µs 5000
#define MAX_PULSE_PACE_µs 63000

typedef struct {
uint8_t elcon[2];
uint8_t phase;
uint8_t pace_ms;
uint8_t elcon[2];
uint16_t pace_µs;
uint16_t nr_of_pulses;
uint16_t pulse_width_¼_µs;
uint8_t rfu;
uint8_t phase;
} Burst;

typedef struct {
int16_t delta_width_¼_µs; // [0.25 µs]. Changes the duration of a pulse.
int8_t delta_pace_µs; // [µs]. Modifies the time between pulses.
int8_t delta_amplitude; // In units of 1/255 of the set maximum.
int8_t delta_width_¼_µs; // [0.25 µs]. Changes the duration of a pulse.
int8_t delta_pace_µs; // [µs]. Modifies the time between pulses.
} Deltas;


bool Burst_isValid(Burst const *);
uint32_t Burst_duration_µs(Burst const *);
void Burst_applyDeltas(Burst *, Deltas const *);

#endif
4 changes: 2 additions & 2 deletions firmware/inc/pattern_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ typedef struct {
char const *name;
uint8_t const (*pattern)[2];
uint16_t nr_of_elcons;
uint8_t pace_ms;
uint8_t nr_of_steps;
uint16_t pace_µs;
uint16_t nr_of_reps;
uint8_t nr_of_steps;
} PatternDescr;

typedef struct {
Expand Down
17 changes: 8 additions & 9 deletions firmware/inc/pulse_train.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,18 @@
#include "burst.h"

typedef struct _PulseTrain PulseTrain; // Opaque type.
typedef uint8_t pulse_train_size_t;

// Class method.
pulse_train_size_t PulseTrain_size();
uint16_t PulseTrain_size();

// Instance methods.
PulseTrain *PulseTrain_init(PulseTrain *, uint8_t seq_nr, uint32_t timestamp, Burst const *burst);
void PulseTrain_clearDeltas(PulseTrain *);
void PulseTrain_setDeltas(PulseTrain *, int16_t delta_width_¼_µs, int8_t delta_amplitude, int8_t delta_pace_µs);
uint16_t PulseTrain_amplitude(PulseTrain const *);
uint8_t PulseTrain_pulseWidth(PulseTrain const *);
Burst const *PulseTrain_getBurst(PulseTrain const *, Burst *);
void PulseTrain_getDeltas(PulseTrain const *, Deltas *);
void PulseTrain_print(PulseTrain const *, uint16_t sz);
void PulseTrain_clearDeltas(PulseTrain *);
void PulseTrain_setDeltas(PulseTrain *, int8_t delta_width_¼_µs, int8_t delta_pace_µs);
uint16_t PulseTrain_amplitude(PulseTrain const *);
uint8_t PulseTrain_pulseWidth(PulseTrain const *);
Burst const *PulseTrain_getBurst(PulseTrain const *, Burst *);
Deltas const *PulseTrain_getDeltas(PulseTrain const *, uint16_t sz, Deltas *);
void PulseTrain_print(PulseTrain const *, uint16_t sz);

#endif
29 changes: 11 additions & 18 deletions firmware/src/bsp_stm32g071.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ typedef struct {
uint16_t volatile adc_1_samples[3]; // Must match the number of ADC1 ranks.
uint16_t V_prim_mV;
uint16_t pulse_seqnr;
uint8_t pulse_phase;
Burst burst;
Deltas deltas;
} BSP;

// The interrupt request priorities, from high to low.
Expand All @@ -104,7 +105,7 @@ enum { // STM32G0xx MCUs have 4 interrupt priority levels.
IRQ_PRIO_ADC1, IRQ_PRIO_EXTI = IRQ_PRIO_ADC1
};

// Ensure the following consts refer to the same timer.
// Ensure the following three consts refer to the same timer.
static TIM_TypeDef *const pulse_timer = TIM1; // Advanced 16-bit timer.
static IRQn_Type const pulse_timer_upd_irq = TIM1_BRK_UP_TRG_COM_IRQn;
static IRQn_Type const pulse_timer_cc_irq = TIM1_CC_IRQn;
Expand Down Expand Up @@ -383,13 +384,6 @@ static uint64_t ticksSinceBoot()
return *(uint64_t *)ticks_since_boot;
}


static uint16_t pulsePaceMillisecondsToTicks(uint8_t pace_ms)
{
uint32_t const pace_ticks = (PULSE_TIMER_FREQ_Hz * pace_ms) / 1000;
return pace_ticks <= 0xffff ? (uint16_t)pace_ticks : 0xffff;
}

/**
* @brief Calculate the value (0..4095) for the 12-bit DAC to set the desired primary voltage [mV].
* @note Assuming R15 = 115 kΩ, R18 = 13 kΩ and R19 = 42.2 kΩ (Refer to the schematic).
Expand Down Expand Up @@ -490,14 +484,16 @@ void TIM1_CC_IRQHandler(void)
pulse_timer->SR &= ~TIM_SR_CC1IF;
bsp.pulse_seqnr += 1;
// BSP_logf("CC1 %hu\n", bsp.pulse_seqnr);
Burst_applyDeltas(&bsp.burst, &bsp.deltas);
}
if ((pulse_timer->DIER & TIM_DIER_CC2IE) && (pulse_timer->SR & TIM_SR_CC2IF)) {
pulse_timer->SR &= ~TIM_SR_CC2IF;
bsp.pulse_seqnr += 1;
// BSP_logf("CC2 %hu\n", bsp.pulse_seqnr);
Burst_applyDeltas(&bsp.burst, &bsp.deltas);
}
if (bsp.pulse_seqnr == pulse_timer->RCR + 1) {
EventQueue_postEvent(bsp.pulse_delegate_queue, ET_BURST_COMPLETED, NULL, 0);
EventQueue_postEvent(bsp.pulse_delegate_queue, ET_BURST_COMPLETED, (uint8_t const *)&bsp.pulse_seqnr, sizeof bsp.pulse_seqnr);
}
if (pulse_timer->SR & 0xcffe0) {
BSP_logf("Pt SR=0x%x\n", pulse_timer->SR & 0xcffe0);
Expand Down Expand Up @@ -638,7 +634,7 @@ void BSP_init()

char const *BSP_firmwareVersion()
{
return "v0.45-beta";
return "v0.47-beta";
}


Expand Down Expand Up @@ -825,14 +821,11 @@ uint16_t BSP_setPrimaryVoltage_mV(uint16_t V_prim_mV)
}


bool BSP_startBurst(Burst const *burst)
bool BSP_startBurst(Burst const *burst, Deltas const *deltas)
{
M_ASSERT(burst->pace_ms >= 5); // Repetition rate <= 200 Hz.
M_ASSERT(burst->pace_ms <= 65); // Repetition rate > 15 Hz.
M_ASSERT(burst->pulse_width_¼_µs != 0);
M_ASSERT(burst->nr_of_pulses != 0);

pulse_timer->ARR = pulsePaceMillisecondsToTicks(burst->pace_ms) - 1;
bsp.burst = *burst;
bsp.deltas = *deltas;
pulse_timer->ARR = burst->pace_µs - 1;
pulse_timer->RCR = burst->nr_of_pulses - 1;
pulse_timer->CNT = 0;
pulse_timer->SR &= ~(TIM_SR_CC1IF | TIM_SR_CC2IF);
Expand Down
44 changes: 44 additions & 0 deletions firmware/src/burst.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* burst.c
*
* NOTICE (do not remove):
* This file is part of project NeoDK (https://github.com/Onwrikbaar/NeoDK).
* See https://github.com/Onwrikbaar/NeoDK/blob/main/LICENSE.txt for full license details.
*
* Created on: 9 Jan 2025
* Author: mark
* Copyright 2025 Neostim™
*/

#include "burst.h"


bool Burst_isValid(Burst const *me)
{
// Pulse repetition rate must be in [16..200] Hz.
if (me->pace_µs < (MIN_PULSE_PACE_µs)) return false;
if (me->pace_µs > (MAX_PULSE_PACE_µs)) return false;
if (me->pulse_width_¼_µs < MIN_PULSE_WIDTH_¼_µs) return false;
if (me->nr_of_pulses == 0) return false;
return true;
}


uint32_t Burst_duration_µs(Burst const *burst)
{
return burst->nr_of_pulses * burst->pace_µs;
}


void Burst_applyDeltas(Burst *me, Deltas const *deltas)
{
int32_t new_pw = me->pulse_width_¼_µs + deltas->delta_width_¼_µs;
if (new_pw < MIN_PULSE_WIDTH_¼_µs) new_pw = MIN_PULSE_WIDTH_¼_µs;
if (new_pw > MAX_PULSE_WIDTH_¼_µs) new_pw = MAX_PULSE_WIDTH_¼_µs;
me->pulse_width_¼_µs = new_pw;

int32_t new_pace = me->pace_µs + deltas->delta_pace_µs;
if (new_pace < MIN_PULSE_PACE_µs) new_pace = MIN_PULSE_PACE_µs;
else if (new_pace > MAX_PULSE_PACE_µs) new_pace = MAX_PULSE_PACE_µs;
me->pace_µs = new_pace;
}
2 changes: 1 addition & 1 deletion firmware/src/pattern_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,6 @@ bool PatternIterator_getNextBurst(PatternIterator *me, Burst *burst)
burst->elcon[0] = elcon[0];
burst->elcon[1] = elcon[1];
burst->pulse_width_¼_µs = me->pulse_width_micros * 4;
burst->pace_ms = me->pattern_descr->pace_ms;// Yields 1000/pace_ms pulses per second.
burst->pace_µs = me->pattern_descr->pace_µs;
return true;
}
62 changes: 24 additions & 38 deletions firmware/src/pulse_train.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Copyright 2019..2025 Neostim™
*/

#include <stddef.h>
#include <string.h>

#include "bsp_dbg.h"
Expand All @@ -19,54 +20,41 @@
#include "pulse_train.h"

/**
* This structure specifies a pulse train's polarity, intensity, timing and electrode configuration.
* This 16-byte structure specifies a pulse train's polarity, intensity, timing and electrode configuration.
* Multi-byte members are little-Endian.
*/
struct _PulseTrain {
uint8_t meta; // Type, version, flags, etc., for correct interpretation of this descriptor.
uint8_t sequence_number; // For diagnostics. Wraps around to 0 after 255.
uint8_t phase; // Bits 2..1 select 1 of 4 biphasic output stages. Bit 0 is the selected stage's polarity.
uint8_t amplitude; // Voltage, current or power, in units of 1/255 of the set maximum.
uint8_t pulse_width_µs; // The duration of one pulse [µs].
uint32_t start_time_µs; // When this burst should begin, in microseconds since 'now'.
uint8_t electrode_set[2]; // The (max 8) electrodes connected to each of the two output phases.
uint8_t pulse_width_µs; // The duration of one pulse [µs].
uint8_t pace_ms; // [1..255] milliseconds between the start of consecutive pulses.
uint16_t nr_of_pulses; // Length of this burst.
uint8_t nr_of_same_phase; // Bits 4..0: number of pulses before changing polarity (max 31, 0 means never).
// The following three members [-128..127] are applied after each pulse.
uint8_t pace_ms; // [1..63] (bits 5..0) milliseconds between the start of consecutive pulses.
uint8_t amplitude; // Voltage, current or power, in units of 1/255 of the set maximum.
// The following two members [-128..127] are applied after each pulse.
int8_t delta_pulse_width_¼_µs;// [0.25 µs]. Changes the duration of a pulse.
int8_t delta_pace_µs; // [µs]. Modifies the time between pulses.
int8_t delta_amplitude; // In units of 1/255 of the set maximum.
// BLE 4.0 / 4.1 guaranteed ATT payload size is 20 bytes, so we have a couple to spare.
uint8_t reserved_for_future_use[2];
};

/*
static void applyDeltaPace(PulseTrain *me)
{
int16_t new_pace_ms = me->pace_ms + me->delta_pace_µs;
if (new_pace_ms < 0) new_pace_ms = 0;
else if (new_pace_ms > 255) new_pace_ms = 255;
me->pace_ms = new_pace_ms;
}
*/
/*
* Below are the functions implementing this module's interface.
*/

pulse_train_size_t PulseTrain_size()
uint16_t PulseTrain_size()
{
return sizeof(PulseTrain);
}


/*
PulseTrain *PulseTrain_copy(void *addr, pulse_train_size_t nb, PulseTrain const *original)
{
if (addr == NULL || nb < PulseTrain_size()) return NULL;
if (original == NULL) return memset(addr, 0, nb);
return memcpy(addr, original, PulseTrain_size());
}

*/

PulseTrain *PulseTrain_init(PulseTrain *me, uint8_t seq_nr, uint32_t timestamp, Burst const *burst)
{
Expand All @@ -77,22 +65,22 @@ PulseTrain *PulseTrain_init(PulseTrain *me, uint8_t seq_nr, uint32_t timestamp,
me->electrode_set[1] = burst->elcon[1];
me->phase = burst->phase;
me->amplitude = 0;
me->pace_ms = burst->pace_ms;
me->pace_ms = burst->pace_µs / 1000;
me->nr_of_pulses = burst->nr_of_pulses;
me->pulse_width_µs = (burst->pulse_width_¼_µs + 2) / 4;
return me;
}


uint16_t PulseTrain_amplitude(PulseTrain const *me)
uint8_t PulseTrain_pulseWidth(PulseTrain const *me)
{
return me->amplitude;
return me->pulse_width_µs;
}


uint8_t PulseTrain_pulseWidth(PulseTrain const *me)
uint16_t PulseTrain_amplitude(PulseTrain const *me)
{
return me->pulse_width_µs;
return me->amplitude;
}


Expand All @@ -101,33 +89,31 @@ Burst const *PulseTrain_getBurst(PulseTrain const *me, Burst *burst)
burst->elcon[0] = me->electrode_set[0];
burst->elcon[1] = me->electrode_set[1];
burst->phase = me->phase;
burst->pace_ms = me->pace_ms;
burst->pace_µs = me->pace_ms * 1000;
burst->pulse_width_¼_µs = me->pulse_width_µs * 4;
burst->nr_of_pulses = me->nr_of_pulses;
return burst;
}


void PulseTrain_getDeltas(PulseTrain const *me, Deltas *deltas)
Deltas const *PulseTrain_getDeltas(PulseTrain const *me, uint16_t sz, Deltas *deltas)
{
deltas->delta_width_¼_µs = me->delta_pulse_width_¼_µs;
deltas->delta_pace_µs = me->delta_pace_µs;
deltas->delta_amplitude = me->delta_amplitude;
deltas->delta_width_¼_µs = sz > offsetof(PulseTrain, delta_pulse_width_¼_µs) ? me->delta_pulse_width_¼_µs : 0;
deltas->delta_pace_µs = sz > offsetof(PulseTrain, delta_pace_µs) ? me->delta_pace_µs : 0;
return deltas;
}


void PulseTrain_clearDeltas(PulseTrain *deltas)
void PulseTrain_clearDeltas(PulseTrain *me)
{
deltas->delta_pulse_width_¼_µs = 0;
deltas->delta_pace_µs = 0;
deltas->delta_amplitude = 0;
me->delta_pulse_width_¼_µs = 0;
me->delta_pace_µs = 0;
}


void PulseTrain_setDeltas(PulseTrain *me, int16_t delta_width_¼_µs, int8_t delta_amplitude, int8_t delta_pace_µs)
void PulseTrain_setDeltas(PulseTrain *me, int8_t delta_width_¼_µs, int8_t delta_pace_µs)
{
me->delta_pulse_width_¼_µs = delta_width_¼_µs;
me->delta_amplitude = delta_amplitude;
me->delta_pace_µs = delta_pace_µs;
}

Expand All @@ -137,5 +123,5 @@ void PulseTrain_print(PulseTrain const *me, uint16_t sz)
BSP_logf("Pt %3hhu: t=%u µs, ec=0x%x<>0x%x, phase=%hhu, np=%hu, pace=%hhu ms, amp=%hhu, pw=%hhu µs, Δ=%hhd ¼µs\n",
me->sequence_number, me->start_time_µs, me->electrode_set[0], me->electrode_set[1],
me->phase, me->nr_of_pulses, me->pace_ms, me->amplitude, me->pulse_width_µs,
sz >= 16 ? me->delta_pulse_width_¼_µs : 0);
sz > offsetof(PulseTrain, delta_pulse_width_¼_µs) ? me->delta_pulse_width_¼_µs : 0);
}
Loading

0 comments on commit 4135404

Please sign in to comment.