adc^2
Ondřej Hruška 6 years ago
parent ddfbbeeb95
commit 3584830dc5
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 5
      platform/hw_utils.c
  2. 53
      units/adc/_adc_init.c
  3. 4
      units/adc/_adc_internal.h
  4. 26
      units/adc/unit_adc.c

@ -371,7 +371,10 @@ bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
*presc = (uint16_t) wPresc; *presc = (uint16_t) wPresc;
if (wPresc * wCount == 0) return false; if (wPresc * wCount == 0) return false;
*real_freq = (base_freq / (wPresc * wCount));
if (real_freq != NULL) {
*real_freq = (base_freq / (wPresc * wCount));
}
return true; return true;
} }

@ -28,6 +28,30 @@ error_t UADC_preInit(Unit *unit)
return E_SUCCESS; return E_SUCCESS;
} }
/** Configure frequency */
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
{
struct priv *priv = unit->data;
uint16_t presc;
uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count,
&priv->real_frequency)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
dbg("Frequency error %d ppm, presc %d, count %d",
(int) lrintf(1000000.0f *
((priv->real_frequency - hertz) / (float) hertz)),
(int) presc, (int) count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
return E_SUCCESS;
}
/** Finalize unit set-up */ /** Finalize unit set-up */
error_t UADC_init(Unit *unit) error_t UADC_init(Unit *unit)
{ {
@ -103,19 +127,20 @@ error_t UADC_init(Unit *unit)
// ------------------- CONFIGURE THE TIMER -------------------------- // ------------------- CONFIGURE THE TIMER --------------------------
dbg("Setting up TIMER"); dbg("Setting up TIMER");
{ {
// Find suitable timer values TRY(UADC_SetSampleRate(unit, priv->frequency));
uint16_t presc; // // Find suitable timer values
uint32_t count; // uint16_t presc;
float real_freq; // uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, priv->frequency, true, &presc, &count, &real_freq)) { // float real_freq;
dbg("Failed to resolve timer params."); // if (!solve_timer(PLAT_APB1_HZ, priv->frequency, true, &presc, &count, &real_freq)) {
return E_BAD_VALUE; // dbg("Failed to resolve timer params.");
} // return E_BAD_VALUE;
dbg("Frequency error %d ppm, presc %d, count %d", // }
(int) lrintf(1000000.0f * ((real_freq - priv->frequency) / (float)priv->frequency)), (int) presc, (int) count); // dbg("Frequency error %d ppm, presc %d, count %d",
// (int) lrintf(1000000.0f * ((real_freq - priv->frequency) / (float)priv->frequency)), (int) presc, (int) count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1)); //
LL_TIM_SetAutoReload(priv->TIMx, count - 1); // LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
// LL_TIM_SetAutoReload(priv->TIMx, count - 1);
LL_TIM_EnableARRPreload(priv->TIMx); LL_TIM_EnableARRPreload(priv->TIMx);
LL_TIM_EnableUpdateEvent(priv->TIMx); LL_TIM_EnableUpdateEvent(priv->TIMx);
LL_TIM_SetTriggerOutput(priv->TIMx, LL_TIM_TRGO_UPDATE); LL_TIM_SetTriggerOutput(priv->TIMx, LL_TIM_TRGO_UPDATE);
@ -208,8 +233,10 @@ error_t UADC_init(Unit *unit)
irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit); irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit);
irqd_attach(priv->ADCx, UADC_ADC_EOS_Handler, unit); irqd_attach(priv->ADCx, UADC_ADC_EOS_Handler, unit);
dbg("irqs attached");
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
dbg("ADC done");
return E_SUCCESS; return E_SUCCESS;
} }

@ -40,6 +40,7 @@ struct priv {
uint16_t averaging_factor; //!< Exponential averaging factor 0-1000 uint16_t averaging_factor; //!< Exponential averaging factor 0-1000
// internal state // internal state
float real_frequency;
uint32_t extended_channels_mask; //!< channels bitfield including tsense and vref uint32_t extended_channels_mask; //!< channels bitfield including tsense and vref
float avg_factor_as_float; float avg_factor_as_float;
ADC_TypeDef *ADCx; //!< The ADC peripheral used ADC_TypeDef *ADCx; //!< The ADC peripheral used
@ -126,4 +127,7 @@ void UADC_StartStream(Unit *unit, TF_ID frame_id);
/** End stream */ /** End stream */
void UADC_StopStream(Unit *unit); void UADC_StopStream(Unit *unit);
/** Configure frequency */
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz);
#endif //GEX_F072_ADC_INTERNAL_H #endif //GEX_F072_ADC_INTERNAL_H

@ -15,6 +15,7 @@ enum TplCmd_ {
CMD_READ_SMOOTHED = 1, CMD_READ_SMOOTHED = 1,
CMD_GET_ENABLED_CHANNELS = 10, CMD_GET_ENABLED_CHANNELS = 10,
CMD_GET_SAMPLE_RATE = 11,
CMD_SETUP_TRIGGER = 20, CMD_SETUP_TRIGGER = 20,
CMD_ARM = 21, CMD_ARM = 21,
@ -25,6 +26,7 @@ enum TplCmd_ {
CMD_STREAM_START = 26, CMD_STREAM_START = 26,
CMD_STREAM_STOP = 27, CMD_STREAM_STOP = 27,
CMD_SET_SMOOTHING_FACTOR = 28, CMD_SET_SMOOTHING_FACTOR = 28,
CMD_SET_SAMPLE_RATE = 29,
}; };
/** Handle a request message */ /** Handle a request message */
@ -33,6 +35,8 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
struct priv *priv = unit->data; struct priv *priv = unit->data;
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
// TODO toggling individual channels - would require DMA re-init and various changes in the usage of the struct
switch (command) { switch (command) {
/** /**
* Get enabled channels. * Get enabled channels.
@ -47,6 +51,23 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
com_respond_pb(frame_id, MSG_SUCCESS, &pb); com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS; return E_SUCCESS;
case CMD_SET_SAMPLE_RATE:
{
uint32_t freq = pp_u32(pp);
if (freq == 0) return E_BAD_VALUE;
TRY(UADC_SetSampleRate(unit, freq));
}
// Pass through - send back the obtained sample rate
/**
* Read the real used frequency, expressed as float.
* May differ from the configured or requested value due to prescaller limitations.
*/
case CMD_GET_SAMPLE_RATE:
pb_float(&pb, priv->real_frequency);
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
/** /**
* Set smoothing factor 0-1000. * Set smoothing factor 0-1000.
* pld: u16:factor * pld: u16:factor
@ -117,7 +138,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
const uint8_t source = pp_u8(pp); const uint8_t source = pp_u8(pp);
const uint16_t level = pp_u16(pp); const uint16_t level = pp_u16(pp);
const uint8_t edge = pp_u8(pp); const uint8_t edge = pp_u8(pp);
const uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ... const uint16_t pretrig = pp_u16(pp);
const uint32_t count = pp_u32(pp); const uint32_t count = pp_u32(pp);
const uint16_t holdoff = pp_u16(pp); const uint16_t holdoff = pp_u16(pp);
const bool auto_rearm = pp_bool(pp); const bool auto_rearm = pp_bool(pp);
@ -260,7 +281,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* u32 - sample count (for each channel) * u32 - sample count (for each channel)
*/ */
case CMD_BLOCK_CAPTURE: case CMD_BLOCK_CAPTURE:
// TODO test
dbg("> Block cpt"); dbg("> Block cpt");
if (priv->opmode != ADC_OPMODE_ARMED && if (priv->opmode != ADC_OPMODE_ARMED &&
priv->opmode != ADC_OPMODE_REARM_PENDING && priv->opmode != ADC_OPMODE_REARM_PENDING &&
@ -276,7 +296,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* The stream can be terminated by the stop command. * The stream can be terminated by the stop command.
*/ */
case CMD_STREAM_START: case CMD_STREAM_START:
// TODO test
dbg("> Stream ON"); dbg("> Stream ON");
if (priv->opmode != ADC_OPMODE_ARMED && if (priv->opmode != ADC_OPMODE_ARMED &&
priv->opmode != ADC_OPMODE_REARM_PENDING && priv->opmode != ADC_OPMODE_REARM_PENDING &&
@ -289,7 +308,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* Stop a stream. * Stop a stream.
*/ */
case CMD_STREAM_STOP: case CMD_STREAM_STOP:
// TODO test
dbg("> Stream OFF"); dbg("> Stream OFF");
if (priv->opmode != ADC_OPMODE_STREAM) { if (priv->opmode != ADC_OPMODE_STREAM) {
com_respond_str(MSG_ERROR, frame_id, "Not streaming"); com_respond_str(MSG_ERROR, frame_id, "Not streaming");

Loading…
Cancel
Save