Skip to content

Commit

Permalink
Fix example not compiling, some improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
MX682X committed Oct 6, 2024
1 parent 5b561e3 commit 99fa098
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 89 deletions.
5 changes: 3 additions & 2 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Changelog
This page documents (nearly) all bugfixes and enhancements that produce visible changes in behavior throughout the history of megaTinyCore. Note that this document is maintained by a human, who is - by nature - imperfect (this is also why there are so many bugs to fix); sometimes the changelog may not be updated at the same time as the changes go in, and occasionally a change is missed entirely in the changelog, though this is rare. Change descriptions may be incomplete or unclear; this is not meant to be an indepth reference.
This page documents (nearly) all bugfixes and enhancements that produce visible changes in behavior throughout the history of DxCore. Note that this document is maintained by a human, who is - by nature - imperfect (this is also why there are so many bugs to fix); sometimes the changelog may not be updated at the same time as the changes go in, and occasionally a change is missed entirely in the changelog, though this is rare. Change descriptions may be incomplete or unclear; this is not meant to be an indepth reference.

## Planned changes not yet implemented
These items are in addition to what was listed under changes already in release.
Expand All @@ -10,12 +10,13 @@ These items are in addition to what was listed under changes already in release.
* Bugfix: Make serialupdi work with EA.
* Enhancement: Implement sleep library
* Re-add SPI attach and detach.
* Ensure libraries in sync with DxCore.
* Ensure libraries in sync with megaTinyCore.

## Planned changes implemented in github
These are typically planned for release in a future version (usually the next one) as noted.
* Update - was not gods of C, it was a gang of rogue peripherals. After being held captive and tortured by WEX Luther and his cronies, core developer has escaped said malicious preipherals. While held captive, my computer and equipment were sabotaged by their henchmen. Particular care in restraining WEX Luther to be taken to ensure that end users do not face such attacks.
* Add support for not-yet-announced S class DA-series parts, which are identical but for having the new EB-series lockdown thingie. There are no changes needed.
* Support for the PTC peripheral on DA parts

### 1.5.11 (Emergency fix)
* At some point in the recent past, I must have angered the gods of C, and suddenly millis disabled stopped working - the system would hang (actually, with in-depth investigation, it was shown to be bootlooping - before it called init(), it was calling 0x0000 (a dirty reset) instead of eliding a weakly defined function with nothing in the body except a return, or with an empty body. Why was it doing this? And why only when millis was disabled?). millis disabled is a key piece of core functionality, necessitating an urgent fix. Moving the definitions into main.cpp resolved this issue. (#485)
Expand Down
18 changes: 11 additions & 7 deletions megaavr/libraries/PTC/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,17 @@ Different pins have a different parasitic capacitance. I suspect this is depends
### Tuning of nodes

In order to ease the use of the PTC module, the ptc_add_* functions will initialize the cap_sensor_t struct with some default values, like the CC value mentioned above. That values can be easily changed and will be applied the next time a conversion of said node starts. Here is a list:
- Analog Gain. Increases the sensitivity of the electrode by adjusting a capacitor on a integrator (I think) (1x Gain)
- Digital Gain. Defines the amount of ADC Oversampling. Will not affect the count value, as it is internally right-shifted. (16x Oversampled)
- Charge Share Delay. Affects the Sample length of the ADC. (0 extra clocks)
- Prescaler. It is possible to slow down the ADC clock by adjusting the Prescaler. (Depends on CPU clock, targeted: 1MHz +/- 25%)
- Serial Resistor. Allows to change the serial resistor between the Cc and the node. Fixed at 100k for Self-Cap. Creates RC-low-pass filter.

If a node is not sensitive enough, you can increase the Analog Gain (if it becomes too sensitive, an increase of the thresholds might be needed). However it is better to have a bigger node to begin with because the bigger the area, the higher is the capacitance delta.
- `uint8_t ptc_node_set_gain(cap_sensor_t *node, ptc_gain_t gain)`. Increases the sensitivity of the electrode by adjusting a capacitor on the integrator (I think). Defaults to 1x Gain.
- Valid values are: `PTC_GAIN_1`, `PTC_GAIN_2`, `PTC_GAIN_4`, `PTC_GAIN_8`, `PTC_GAIN_16`, `PTC_GAIN_32` (Tiny only).
- `uint8_t ptc_node_set_oversamples(cap_sensor_t *node, uint8_t ovs)`. Defines the amount of ADC Oversampling. Will not affect the count value, as it is internally right-shifted. Valid values are in the range from 0 to 6 resulting in 1x, 2x, 4x, 8x, 16x, 32x, 64x oversampling. Defaults to 16x.
- `uint8_t ptc_node_set_charge_share_delay(cap_sensor_t *node, uint8_t csd)`. Affects the Sample length of the ADC. This does pretty much the same thing as ADC.SAMPCTRL register. Valid range is from 0 to 31. Defaults to 0 extra clocks.
- `uint8_t ptc_node_set_prescaler(cap_sensor_t *node, ptc_presc_t presc)`. It is possible to slow down the ADC/PTC clock by adjusting the Prescaler. The ADC/PTC Clock should be between 1 and 2 MHz. The library calculates the default based on F_CPU.
- Valid values for Tiny are: `PTC_PRESC_DIV2_gc`, `PTC_PRESC_DIV4_gc`, `PTC_PRESC_DIV8_gc`, `PTC_PRESC_DIV16_gc`, `PTC_PRESC_DIV32_gc`, `PTC_PRESC_DIV64_gc`, `PTC_PRESC_DIV128_gc`, `PTC_PRESC_DIV256_gc`.
- Valid values for DA are: `PTC_PRESC_DIV2_gc`, `PTC_PRESC_DIV4_gc`, `PTC_PRESC_DIV6_gc`, `PTC_PRESC_DIV8_gc`, `PTC_PRESC_DIV10_gc`, `PTC_PRESC_DIV12_gc`, `PTC_PRESC_DIV14_gc`, `PTC_PRESC_DIV16_gc`.
- `uint8_t ptc_node_set_resistor(cap_sensor_t *node, ptc_rsel_t res)`. Allows to change the serial resistor between the Cc and the node. Fixed at 100k for Self-Cap. Defaults to 50k for Mutual-Cap.
- Valid Values are: `RSEL_VAL_0`, `RSEL_VAL_20`, `RSEL_VAL_50`, `RSEL_VAL_70`, `RSEL_VAL_80` (DA only), `RSEL_VAL_100`, `RSEL_VAL_120` (DA only), `RSEL_VAL_200`.

If a node is not sensitive enough, you can increase the Analog Gain (if it becomes too sensitive, an increase of the thresholds might be needed). However it is better to have a bigger electrode to begin with because the bigger the area, the higher is the capacitance delta.

### Global settings of the State-machine
The state-machine, which changes the node's state between Calibration, touch, no touch, etc. uses some variables that are valid for all nodes, those are:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include <ptc.h>
/*
* This example creates four different sensing nodes. of two different types.
* PA4 and PA5 are the self-cap lines with PB0 acting as shield pin.
* PA6 and PA7 are the Y-Lines with PB1 acting as the X-line.
* PA4 and PA5 are the self-cap lines with PA0 acting as shield pin.
* PA6 and PA7 are the Y-Lines with PA1 acting as the X-line.
* PTC_CB_EVENT_CONV_MUTUAL_CMPL and
* PTC_CB_EVENT_CONV_SHIELD_CMPL can be used to change the type that is converted.
* This will create an interlaced conversion, but it is not mandatory to do so.
Expand All @@ -16,11 +16,11 @@ cap_sensor_t nodes[4];

void setup() {
// put your setup code here, to run once:
ptc_add_selfcap_node(&nodes[0], PIN_TO_PTC(PIN_PB0), PIN_TO_PTC(PIN_PA4));
ptc_add_selfcap_node(&nodes[1], PIN_TO_PTC(PIN_PB0), PIN_TO_PTC(PIN_PA5));
ptc_add_selfcap_node(&nodes[0], PIN_TO_PTC(PIN_PA0), PIN_TO_PTC(PIN_PA4));
ptc_add_selfcap_node(&nodes[1], PIN_TO_PTC(PIN_PA0), PIN_TO_PTC(PIN_PA5));

ptc_add_mutualcap_node(&nodes[2], PIN_TO_PTC(PIN_PB1), PIN_TO_PTC(PIN_PA6));
ptc_add_mutualcap_node(&nodes[3], PIN_TO_PTC(PIN_PB1), PIN_TO_PTC(PIN_PA7));
ptc_add_mutualcap_node(&nodes[2], PIN_TO_PTC(PIN_PA1), PIN_TO_PTC(PIN_PA6));
ptc_add_mutualcap_node(&nodes[3], PIN_TO_PTC(PIN_PA1), PIN_TO_PTC(PIN_PA7));

MySerial.begin(115200);
MySerial.println("Hello World!");
Expand Down
129 changes: 69 additions & 60 deletions megaavr/libraries/PTC/src/ptc.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ void ptc_process_measurement(cap_sensor_t *node);
// Handles (initial) calibration
uint8_t ptc_process_calibrate(cap_sensor_t *node);

// Handles adjustment of the reference value when a button is not pressed
void ptc_process_adjust();

void ptc_set_registers(cap_sensor_t *node);


cap_sensor_t *firstNode = NULL;
Expand Down Expand Up @@ -73,19 +70,11 @@ ptc_lib_sm_set_t *ptc_get_sm_settings() {
#if defined (__PTC_Tiny__)
#define PTC_DEFAULT_SC_CC 0x0567
#define PTC_DEFAULT_MC_CC 0x0234

const uint8_t ptc_a_gain_lut[] = {
0x3F, 0x1C, 0x0B,
0x05, 0x03, 0x01,
};
#define PTC_GAIN_BASE 0x003F
#elif defined (__PTC_DA__)
#define PTC_DEFAULT_SC_CC 0x00F0
#define PTC_DEFAULT_MC_CC 0x00A0

const uint8_t ptc_a_gain_lut[] = {
0x1F, 0x0F, 0x07,
0x03, 0x01
};
#define PTC_GAIN_BASE 0x001F
#endif


Expand Down Expand Up @@ -113,23 +102,28 @@ uint8_t ptc_node_set_thresholds(cap_sensor_t *node, int16_t th_in, int16_t th_ou
if (NULL == node) {
return PTC_LIB_BAD_POINTER;
}
node->touch_in_th = th_in;
node->touch_out_th = th_out;
if (th_in != 0) {
node->touch_in_th = th_in;
}
if (th_out != 0) {
node->touch_out_th = th_out;
}
return PTC_LIB_SUCCESS;
}


// Change Resistor Setting. Note: Only has an effect on mutual sensors
uint8_t ptc_node_set_resistor(cap_sensor_t *node, uint8_t res) {
uint8_t ptc_node_set_resistor(cap_sensor_t *node, ptc_rsel_t res) {
PTC_CHECK_FOR_BAD_POINTER(node);

if (res > RSEL_MAX) {
return PTC_LIB_BAD_ARGUMENT;
}

res &= 0x0F;
res <<= 0x04;
if (node->type & NODE_MUTUAL_bm) {
uint8_t presc = node->hw_rsel_presc & 0x0F;
presc |= ((res & 0x0F) << 4);
presc |= res;
node->hw_rsel_presc = presc;
return PTC_LIB_SUCCESS;
}
Expand All @@ -139,50 +133,62 @@ uint8_t ptc_node_set_resistor(cap_sensor_t *node, uint8_t res) {


// Change prescaler. Recommended ADC frequency: < 1.5MHz, but max 3 factors below
uint8_t ptc_node_set_prescaler(cap_sensor_t *node, uint8_t presc) {
uint8_t ptc_node_set_prescaler(cap_sensor_t *node, ptc_presc_t presc) {
PTC_CHECK_FOR_BAD_POINTER(node);

if ((presc > (PTC_PRESC_DEFAULT + 2)) || (presc < PTC_PRESC_DEFAULT)) {
return PTC_LIB_BAD_ARGUMENT;
}

presc &= 0x0F;
uint8_t res = node->hw_rsel_presc & 0xF0;
res |= (presc & 0x0F);
res |= presc;
node->hw_rsel_presc = res;
return PTC_LIB_SUCCESS;
}


uint8_t ptc_node_set_gain(cap_sensor_t *node, uint8_t aGain, uint8_t dGain) {
uint8_t ptc_node_set_gain(cap_sensor_t *node, ptc_gain_t gain) {
PTC_CHECK_FOR_BAD_POINTER(node);

#if defined (__PTC_Tiny__)
if (aGain > 0x05) {
if (__builtin_constant_p(aGain)) {
badArg("Analog Gain too high. Max Analog Gain Value is 0x05 (equals 32x)");
if (gain >= PTC_GAIN_MAX) {
if (__builtin_constant_p(gain)) {
badArg("Analog Gain too high. Max Analog Gain Value is 0x3F (Tiny) / 0x1F (DA)");
}
return PTC_LIB_BAD_ARGUMENT;
}
#elif defined (__PTC_DA__)
if (aGain > 0x04) {
if (__builtin_constant_p(aGain)) {
badArg("Analog Gain too high. Max Analog Gain Value is 0x04 (equals 16x)");
}
return PTC_LIB_BAD_ARGUMENT;
}
#endif
gain = PTC_GAIN_MAX - gain;
gain <<= 4;
uint8_t ovs = node->hw_gain_ovs & 0x0F;
node->hw_gain_ovs = gain | ovs;
return PTC_LIB_SUCCESS;
}

uint8_t ptc_node_set_oversamples(cap_sensor_t *node, uint8_t ovs) {
PTC_CHECK_FOR_BAD_POINTER(node);

if (dGain > 0x06) {
if (__builtin_constant_p(dGain)) {
if (ovs > 0x06) {
if (__builtin_constant_p(ovs)) {
badArg("Digital Gain too high. Max Digital Gain Value is 0x06 (equals 64x)");
}
return PTC_LIB_BAD_ARGUMENT;
}
node->hw_a_d_gain = NODE_GAIN(aGain, dGain);
uint8_t gain = node->hw_gain_ovs & 0xF0;
node->hw_gain_ovs = gain | ovs;
return PTC_LIB_SUCCESS;
}

uint8_t ptc_node_set_charge_share_delay(cap_sensor_t *node, uint8_t csd) {
PTC_CHECK_FOR_BAD_POINTER(node);
if (csd > 15) {
if (__builtin_constant_p(csd)) {
badArg("Charge Share Delay too high, maximum value is 15");
}
return PTC_LIB_BAD_ARGUMENT;
}

node->hw_csd = csd;
return PTC_LIB_SUCCESS;
}

/*
* Two functions to suspend and resume of the normal PTC operation, however,
Expand Down Expand Up @@ -291,7 +297,7 @@ uint8_t ptc_add_node(cap_sensor_t *node, uint8_t *pCh, const uint8_t type) {
}
#endif

node->hw_a_d_gain = NODE_GAIN(0, ADC_SAMPNUM_ACC16_gc);
node->hw_gain_ovs = NODE_GAIN(0, ADC_SAMPNUM_ACC16_gc);

if (type & NODE_MUTUAL_bm) {
node->touch_in_th = 10;
Expand Down Expand Up @@ -878,7 +884,7 @@ void ptc_init_conversion(uint8_t nodeType) {
if (NULL != lowPowerNode) {
pPTC->INTCTRL = ADC_WCMP_bm; // Wakeup only above of window
pPTC->CTRLE = ADC_WINCM_ABOVE_gc;
pPTC->WINHT = (lowPowerNode->reference + lowPowerNode->touch_in_th) << (lowPowerNode->hw_a_d_gain & 0x0F);
pPTC->WINHT = (lowPowerNode->reference + lowPowerNode->touch_in_th) << (lowPowerNode->hw_gain_ovs & 0x0F);
ptc_lib_state = PTC_LIB_EVENT;
ptc_start_conversion(lowPowerNode);
} else {
Expand Down Expand Up @@ -924,7 +930,7 @@ void ptc_init_conversion(uint8_t nodeType) {
if (NULL != lowPowerNode) {
pPTC->INTCTRL = ADC_WCMP_bm; // Wakeup only above of window
pPTC->CTRLE = ADC_WINCM_ABOVE_gc;
pPTC->WINHT = (lowPowerNode->reference + lowPowerNode->touch_in_th) << (lowPowerNode->hw_a_d_gain & 0x0F);
pPTC->WINHT = (lowPowerNode->reference + lowPowerNode->touch_in_th) << (lowPowerNode->hw_gain_ovs & 0x0F);
ptc_lib_state = PTC_LIB_EVENT;
ptc_start_conversion(lowPowerNode);
} else {
Expand All @@ -951,25 +957,15 @@ void ptc_start_conversion(cap_sensor_t *node) {
}

currConvNode = node;

ptc_set_registers(node);
}

void ptc_set_registers(cap_sensor_t *node) {

PTC_t *pPTC;
_fastPtr_d(node, node); // Sometimes it takes the compiler a bit more of convincing...
_fastPtr_d(pPTC, &PTC);

if (NULL == node) {
return;
_fastPtr_d(node, node);
uint8_t analogGain = PTC_GAIN_MAX;
if (node->stateMachine != PTC_SM_NOINIT_CAL) {
analogGain = node->hw_gain_ovs / 16; // A little workaround as >> 4 is kinda broken sometimes.
}

uint8_t lut_index = 0;
if ((node->state.disabled == 0) && (node->stateMachine != PTC_SM_NOINIT_CAL)) {
lut_index = node->hw_a_d_gain / 16; // A little workaround as >> 4 is kinda broken sometimes.
}
uint8_t analogGain = ptc_a_gain_lut[lut_index];

uint8_t chargeDelay = node->hw_csd;

#if defined(__PTC_Tiny__)
Expand All @@ -988,10 +984,23 @@ void ptc_set_registers(cap_sensor_t *node) {
pPTC->CTRLP |= 0x03;

#elif defined(__PTC_DA__)
memcpy((void *)pPTC->XBM, node->hw_xCh_bm, sizeof(ptc_ch_arr_t));
memcpy((void *)pPTC->YBM, node->hw_yCh_bm, sizeof(ptc_ch_arr_t));
((uint8_t*)&pPTC->XBM)[0] = node->hw_xCh_bm[0]; // avoid memcpy to reduce register pressure
((uint8_t*)&pPTC->XBM)[1] = node->hw_xCh_bm[1]; // avoiding memcpy means we can put &PTC
((uint8_t*)&pPTC->XBM)[2] = node->hw_xCh_bm[2]; // and node in the Z/Y-Registers and just use
((uint8_t*)&pPTC->XBM)[3] = node->hw_xCh_bm[3]; // the fast and memory efficient std/ldd instructions
((uint8_t*)&pPTC->XBM)[4] = node->hw_xCh_bm[4];

((uint8_t*)&pPTC->YBM)[0] = node->hw_yCh_bm[0];
((uint8_t*)&pPTC->YBM)[1] = node->hw_yCh_bm[1];
((uint8_t*)&pPTC->YBM)[2] = node->hw_yCh_bm[2];
((uint8_t*)&pPTC->YBM)[3] = node->hw_yCh_bm[3];
((uint8_t*)&pPTC->YBM)[4] = node->hw_yCh_bm[4];
#if __PTC_Pincount__ >= 40
((uint8_t*)&pPTC->XBM)[5] = node->hw_xCh_bm[5];
((uint8_t*)&pPTC->YBM)[5] = node->hw_yCh_bm[5];
#endif

if (chargeDelay < 0x7B) {
if (chargeDelay < 0x1B) {
chargeDelay += 4;
} else {
chargeDelay = 0x1F;
Expand All @@ -1014,7 +1023,7 @@ void ptc_set_registers(cap_sensor_t *node) {

pPTC->COMP = node->hw_compCaps;
pPTC->AGAIN = analogGain;
pPTC->CTRLB = node->hw_a_d_gain & 0x0F;
pPTC->CTRLB = node->hw_gain_ovs & 0x0F;
pPTC->RSEL = node->hw_rsel_presc / 16;

pPTC->CTRLA = ADC_RUNSTBY_bm | ADC_ENABLE_bm; /* 0x81 */
Expand Down Expand Up @@ -1076,7 +1085,7 @@ void ptc_eoc(void) {
pPTC->CTRLA = 0x00;
uint8_t flags = pPTC->INTFLAGS; // save the flags before they get cleared by RES read
uint16_t rawVal = pPTC->RES; // clears ISR flags
uint8_t oversampling = pCurrentNode->hw_a_d_gain & 0x0F;
uint8_t oversampling = pCurrentNode->hw_gain_ovs & 0x0F;
pCurrentNode->sensorData = rawVal >> oversampling;

//currConvNode->sensorData = pPTC->RES_TRUE;
Expand Down
16 changes: 12 additions & 4 deletions megaavr/libraries/PTC/src/ptc.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,25 @@ void ptc_set_next_conversion_type(ptc_node_type_t type);
void ptc_process(uint16_t currTime);


// Set the threshold for touch detection and away from touch for a node
// Set the threshold for touch detection and away from touch for a node.
// a "0" will be interpreted as don't change
uint8_t ptc_node_set_thresholds(cap_sensor_t *node, int16_t th_in, int16_t th_out);


// Change Resistor Setting. Note: Only has an effect on mutual sensors
uint8_t ptc_node_set_resistor(cap_sensor_t *node, uint8_t res);
uint8_t ptc_node_set_resistor(cap_sensor_t *node, ptc_rsel_t res);

// Change prescaler.
uint8_t ptc_node_set_prescaler(cap_sensor_t *node, uint8_t presc);
uint8_t ptc_node_set_prescaler(cap_sensor_t *node, ptc_presc_t presc);

uint8_t ptc_node_set_gain(cap_sensor_t *node, uint8_t aGain, uint8_t dGain);
// Sets the gain through adjusting the charge integrator (increases the sensitivity (and noise))
uint8_t ptc_node_set_gain(cap_sensor_t *node, ptc_gain_t gain);

// Sets the number of oversamples. (the value is right-shifted automatically (reduces noise))
uint8_t ptc_node_set_oversamples(cap_sensor_t *node, uint8_t ovs);

// Sets the number of additional PTC Clocks for sampling a node. See also: ADC.SAMPCTRL
uint8_t ptc_node_set_charge_share_delay(cap_sensor_t *node, uint8_t csd);

// this is an internal function, there is no sense in calling it directly
uint8_t ptc_add_node(cap_sensor_t *node, uint8_t *pCh, const uint8_t type);
Expand Down
8 changes: 4 additions & 4 deletions megaavr/libraries/PTC/src/ptc_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ typedef struct PTC_struct {
#define PRSC_MAX ADC_PRESC_DIV256_gc

#if F_CPU >= 12000000 // 16 MHz / 16 = 1.0 MHz, 20 MHz / 16 = 1.25 MHz
#define PTC_PRESC_DEFAULT ADC_PRESC_DIV16_gc
#define PTC_PRESC_DEFAULT PTC_PRESC_DIV16_gc
#elif F_CPU >= 6000000 // 8 MHz / 8 = 1.0 MHz, 10 MHz / 8 = 1.25 MHz
#define PTC_PRESC_DEFAULT ADC_PRESC_DIV8_gc
#define PTC_PRESC_DEFAULT PTC_PRESC_DIV8_gc
#elif F_CPU >= 3000000 // 4 MHz / 4 = 1.0 MHz, 5 MHz / 4 = 1.25 MHz
#define PTC_PRESC_DEFAULT ADC_PRESC_DIV4_gc
#define PTC_PRESC_DEFAULT PTC_PRESC_DIV4_gc
#else // 1 MHz / 2 = 500 kHz - the lowest setting
#define PTC_PRESC_DEFAULT ADC_PRESC_DIV2_gc
#define PTC_PRESC_DEFAULT PTC_PRESC_DIV2_gc
#endif

#elif defined (__PTC_DA__)
Expand Down
Loading

0 comments on commit 99fa098

Please sign in to comment.