diff --git a/firmware/hw_layer/AdcConfiguration.h b/firmware/hw_layer/AdcConfiguration.h index a94426a2b8..6bde754de7 100644 --- a/firmware/hw_layer/AdcConfiguration.h +++ b/firmware/hw_layer/AdcConfiguration.h @@ -22,8 +22,14 @@ public: int conversionCount; int errorsCount; int getAdcValueByIndex(int internalIndex) const; + void invalidateSamplesCache(); - adcsample_t samples[ADC_MAX_CHANNELS_COUNT * MAX_ADC_GRP_BUF_DEPTH]; + // This must be aligned on a 32-byte boundary, and be a multiple of 32 bytes long. + // When we invalidate the cache line(s) for ADC samples, we don't want to nuke any + // adjacent data + __ALIGNED(32) adcsample_t samples[ADC_MAX_CHANNELS_COUNT * MAX_ADC_GRP_BUF_DEPTH]; + // Assert multiple of 32 bytes long so we don't stomp on the data after the buffer + static_assert(sizeof(samples) % 32 == 0); int getAdcValueByHwChannel(int hwChannel) const; diff --git a/firmware/hw_layer/adc_inputs.cpp b/firmware/hw_layer/adc_inputs.cpp index 7d96638625..91a999a314 100644 --- a/firmware/hw_layer/adc_inputs.cpp +++ b/firmware/hw_layer/adc_inputs.cpp @@ -256,10 +256,10 @@ static void pwmpcb_fast(PWMDriver *pwmp) { float getMCUInternalTemperature(void) { #if defined(ADC_CHANNEL_SENSOR) float TemperatureValue = adcToVolts(slowAdc.getAdcValueByHwChannel(ADC_CHANNEL_SENSOR)); - TemperatureValue -= 0.760; // Subtract the reference voltage at 25°C + TemperatureValue -= 0.760; // Subtract the reference voltage at 25 deg C TemperatureValue /= .0025; // Divide by slope 2.5mV - TemperatureValue += 25.0; // Add the 25°C + TemperatureValue += 25.0; // Add the 25 deg C return TemperatureValue; #else return 0; @@ -342,6 +342,17 @@ int AdcDevice::getAdcValueByIndex(int internalIndex) const { return values.adc_data[internalIndex]; } +void AdcDevice::invalidateSamplesCache() { +#if PROJECT_CPU == ARCH_STM32F7 + // The STM32F7xx has a data cache + // DMA operations DO NOT invalidate cache lines, since the ARM m7 doesn't have + // anything like a CCI that maintains coherency across multiple bus masters. + // As a result, we have to manually invalidate the D-cache any time we (the CPU) + // would like to read something that somebody else wrote (ADC via DMA, in this case) + SCB_InvalidateDCache_by_Addr(reinterpret_cast(samples), sizeof(samples)); +#endif +} + void AdcDevice::init(void) { hwConfig->num_channels = size(); hwConfig->sqr1 += ADC_SQR1_NUM_CH(size()); @@ -432,6 +443,9 @@ int getSlowAdcCounter() { static void adc_callback_slow(ADCDriver *adcp, adcsample_t *buffer, size_t n) { (void) buffer; (void) n; + + slowAdc.invalidateSamplesCache(); + efiAssertVoid(CUSTOM_ERR_6671, getCurrentRemainingStack() > 128, "lowstck#9c"); /* Note, only in the ADC_COMPLETE state because the ADC driver fires * an intermediate callback when the buffer is half full. */ diff --git a/firmware/hw_layer/hardware.cpp b/firmware/hw_layer/hardware.cpp index 472e0d7cc5..7078a3f65a 100644 --- a/firmware/hw_layer/hardware.cpp +++ b/firmware/hw_layer/hardware.cpp @@ -196,6 +196,7 @@ extern AdcDevice fastAdc; * This method is not in the adc* lower-level file because it is more business logic then hardware. */ void adc_callback_fast(ADCDriver *adcp, adcsample_t *buffer, size_t n) { + fastAdc.invalidateSamplesCache(); (void) buffer; (void) n;