Recently spent a few days hacking/reverse engineering a Xiaomi M365 scooter, decided to write own FW for motor controller that's based on a STM32F103C8T6. New to STM32, it's an uphill battle, especially with unfriendly dev tools, but so far I was able to remove readout protection, flash own FW that blinks LED on board, debug, change clocks, etc..
First thing to do is get ADC feedback from the BLDC shunt current monitors, the voltage at 0A phase current sits at 1.65V on pins 13,14,15, so ADC value should be non-zero. Issue is, no matter how hard I try, value returned by ADC is always 0 (seeing this by inspecting the result variable in debugger). I tried internal temp sensor as well to isolate GPIO setup issues, same thing. I'm using polled ADC, but the idea is to use DMA on all 3 channels, as well as the analog watchdog to handle overcurrent events and cycle-by-cycle current limit.
Attached is the source which pretty much has everything except boilerplate System Workbench generated files. As much as I tried to avoid, HAL is used for everything.
The reason original FW wasn't working is because it was throwing a code, that according to some russian hackers meant issues with shunt calibrations, self-test failure, etc. I probed all the hardware on the board, and compared feedback to MCU with a working unit, and they were all exactly the same, down to the startup self-test waveforms. Now I'm thinking ADC is somehow blown up, but can't confirm, since don't have another STM32 to play with.
TL/DR: noob that can't use STM32 ADC
Anyone can take a look, for obv. mistakes? Also, does any self-test code exist for ADC peripheral a. la IEC 60730?
Some relevant parts of the code:
void setup_adc()
{
...
ADC_ChannelConfTypeDef ADC_ChannelStruct;
HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC1_IRQn);
ADC_HandleStruct.Instance = ADC1;
ADC_HandleStruct.Init.ContinuousConvMode = ENABLE;
ADC_HandleStruct.Init.DiscontinuousConvMode = DISABLE;
ADC_HandleStruct.Init.DataAlign = ADC_DATAALIGN_RIGHT;
ADC_HandleStruct.Init.ExternalTrigConv = ADC_SOFTWARE_START;
ADC_HandleStruct.Init.NbrOfConversion = 1;
ADC_HandleStruct.Init.ScanConvMode = DISABLE;
if(HAL_ADC_Init(&ADC_HandleStruct) != HAL_OK)
{
asm("bkpt 255");
}
ADC_ChannelStruct.Channel = ADC_CHANNEL_16;
ADC_ChannelStruct.Rank = ADC_REGULAR_RANK_1;
ADC_ChannelStruct.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
if(HAL_ADC_ConfigChannel(&ADC_HandleStruct, &ADC_ChannelStruct) != HAL_OK)
{
asm("bkpt 255");
}
}
int main(void)
{
HAL_Init();
enable_clocks();
setup_led();
setup_clocks();
setup_adc();
led_off();
while(1)
{
// ADC measurment & display value
HAL_ADC_Start(&ADC_HandleStruct);
HAL_ADC_PollForConversion(&ADC_HandleStruct, 1000); // 1000 is timeout in miliseconds
ADC_val = HAL_ADC_GetValue(&ADC_HandleStruct);
HAL_ADC_Stop(&ADC_HandleStruct);
}
}