AM32 电调学习–输入获取分析
#define INTERVAL_TIMER TIM2 ; 过零时间测量
psc=31
#define TEN_KHZ_TIMER TIM6 ;tenKhzRoutine frq=1M load=1M/20k
psc=63
#define UTILITY_TIMER TIM17
#define COM_TIMER TIM14 //PeriodElapsedCallback 过零后等待时间中断
psc=31
#define IC_TIMER_REGISTER TIM3
psc=0
PB4 tim3_chn1
一、使用到的变量
dma1chan1 interrupt transfercomplete:
- uint16_t signaltimeout = 0;
- out_put: 0:receiveDshotDma1:
1:sendDshotDma - char dshot_telemetry = 0; dshort检测到标志
processDshot(EXTI4_15_IRQHandler)<--DMA1_Channel1_IRQHandler
- ic_timer_prescaler char ic_timer_prescaler = CPU_FREQUENCY_MHZ / 5;
- output_timer_prescaler
if (CPU_FREQUENCY_MHZ > 100) {
output_timer_prescaler = 1;
} else {
output_timer_prescaler = 0;
}
- char inputSet = 0; 输入方式是否已经决定标志
二、输入端口设置
- PB4设置为tim3 channel1.
- dma1 channel1 ,方向per(halfword)–>memory(word)
- 分频为0
- 双沿触发
三、开始处理
- 在main初始化中调用receiveDshotDma().
- 在dma中断中处理transfercomplete()
void transfercomplete()
{
signaltimeout = 0;
if (armed && dshot_telemetry) {
if (out_put) {
receiveDshotDma();
compute_dshot_flag = 2;
return;
} else {
sendDshotDma();
compute_dshot_flag = 1;
return;
}
}
if (inputSet == 0) {
detectInput();
receiveDshotDma();
return;
}
if (inputSet == 1) {
if (dshot_telemetry) {
if (out_put) {
make_dshot_package(e_com_time);
computeDshotDMA();
receiveDshotDma();
return;
} else {
sendDshotDma();
return;
}
} else {
if (dshot == 1) {
computeDshotDMA();
receiveDshotDma();
}
if (servoPwm == 1) {
if (getInputPinState()) {
buffersize = 3;
} else {
buffersize = 2;
computeServoInput();
}
receiveDshotDma();
}
}
if (!armed) {
if (dshot && (average_count < 8) && (zero_input_count > 5)) {
average_count++;
average_packet_length = average_packet_length + (dma_buffer[31] - dma_buffer[0]);
if (average_count == 8) {
dshot_frametime_high = (average_packet_length >> 3) + (average_packet_length >> 7);
dshot_frametime_low = (average_packet_length >> 3) - (average_packet_length >> 7);
}
}
if (adjusted_input < 0) {
adjusted_input = 0;
}
if (adjusted_input == 0 && calibration_required == 0) { // note this in input..not newinput so it
// will be adjusted be main loop
zero_input_count++;
} else {
zero_input_count = 0;
if (adjusted_input > 1500) {
if (getAbsDif(adjusted_input, last_input) > 50) {
enter_calibration_count = 0;
} else {
enter_calibration_count++;
}
if (enter_calibration_count > 50 && (!high_calibration_set)) {
playBeaconTune3();
calibration_required = 1;
enter_calibration_count = 0;
}
last_input = adjusted_input;
}
}
}
}
}
- 判定输入方式
(A) PPM信号的最小间隔在150us–1500us之间
(B) dshot600的最小间距在100ns-700ns
dshot300的最小间隔城200-1400ns之间
void detectInput()
{
smallestnumber = 20000;
average_signal_pulse = 0;
int lastnumber = dma_buffer[0];
for (int j = 1; j < 31; j++) {
if (dma_buffer[j] - lastnumber > 0) {
if ((dma_buffer[j] - lastnumber) < smallestnumber) {
smallestnumber = dma_buffer[j] - lastnumber;
}
average_signal_pulse += (dma_buffer[j] - lastnumber);
}
lastnumber = dma_buffer[j];
}
average_signal_pulse = average_signal_pulse / 32;
if (dshot == 1) {
checkDshot();
}
if (servoPwm == 1) {
checkServo();
}
if (!dshot && !servoPwm) {
checkDshot();
checkServo();
}
}
void checkServo()
{
if (smallestnumber > 200 && smallestnumber < 20000) {
servoPwm = 1;
ic_timer_prescaler = CPU_FREQUENCY_MHZ - 1;
buffersize = 2;
inputSet = 1;
}
}
void checkDshot()
{
if ((smallestnumber > 1) && (smallestnumber <= 4) && (average_signal_pulse < 60)) {
ic_timer_prescaler = 0;
if (CPU_FREQUENCY_MHZ > 100) {
output_timer_prescaler = 1;
} else {
output_timer_prescaler = 0;
}
// dshot_runout_timer = 1000;
dshot = 1;
buffer_padding = 14;
buffersize = 32;
inputSet = 1;
}
if ((smallestnumber > 4) && (smallestnumber <= 8) && (average_signal_pulse < 100)) {
dshot = 1;
ic_timer_prescaler = 1;
if (CPU_FREQUENCY_MHZ > 100) {
output_timer_prescaler = 3;
} else {
output_timer_prescaler = 1;
}
buffer_padding = 7;
buffersize = 32;
inputSet = 1;
}
}
四、dma的输入和输出
- 输入
void receiveDshotDma()
{
#ifdef USE_TIMER_3_CHANNEL_1
RCC->APBRSTR1 |= LL_APB1_GRP1_PERIPH_TIM3;
RCC->APBRSTR1 &= ~LL_APB1_GRP1_PERIPH_TIM3;
IC_TIMER_REGISTER->CCMR1 = 0x61; //fdts/4 N=6, fdts 是clk_int/ckd[cr1]
IC_TIMER_REGISTER->CCER = 0xa; //cc1np cc1p =11,双沿触发 output disable
#endif
#ifdef USE_TIMER_16_CHANNEL_1
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM16); // de-init timer 2
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM16);
IC_TIMER_REGISTER->CCMR1 = 0x61;
IC_TIMER_REGISTER->CCER = 0xa;
#endif
IC_TIMER_REGISTER->PSC = ic_timer_prescaler;
IC_TIMER_REGISTER->ARR = 0xFFFF;
IC_TIMER_REGISTER->EGR |= TIM_EGR_UG;
out_put = 0;
IC_TIMER_REGISTER->CNT = 0;
DMA1_Channel1->CMAR = (uint32_t)&dma_buffer;
DMA1_Channel1->CPAR = (uint32_t)&IC_TIMER_REGISTER->CCR1;
DMA1_Channel1->CNDTR = buffersize;
DMA1_Channel1->CCR = 0x98b; //9:m-32b p-16b 8: minc 接收 b: en/tc/te
IC_TIMER_REGISTER->DIER |= TIM_DIER_CC1DE; //dma int enable
IC_TIMER_REGISTER->CCER |= IC_TIMER_CHANNEL;
IC_TIMER_REGISTER->CR1 |= TIM_CR1_CEN; //counter enable
}
- 输出:
void sendDshotDma()
{
#ifdef USE_TIMER_3_CHANNEL_1
RCC->APBRSTR1 |= LL_APB1_GRP1_PERIPH_TIM3;
RCC->APBRSTR1 &= ~LL_APB1_GRP1_PERIPH_TIM3;
IC_TIMER_REGISTER->CCMR1 = 0x60;
IC_TIMER_REGISTER->CCER = 0x3; //output enable ,activate low
#endif
#ifdef USE_TIMER_16_CHANNEL_1
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_TIM16); // de-init timer 2
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_TIM16);
IC_TIMER_REGISTER->CCMR1 = 0x60;
IC_TIMER_REGISTER->CCER = 0x3;
#endif
IC_TIMER_REGISTER->PSC = output_timer_prescaler;
IC_TIMER_REGISTER->ARR = 92;
out_put = 1;
LL_TIM_GenerateEvent_UPDATE(IC_TIMER_REGISTER);
DMA1_Channel1->CMAR = (uint32_t)&gcr;
DMA1_Channel1->CPAR = (uint32_t)&IC_TIMER_REGISTER->CCR1;
DMA1_Channel1->CNDTR = 23 + buffer_padding;
DMA1_Channel1->CCR = 0x99b; //9:m-32b p-16b 9: minc 发送 b: en/tc/te
IC_TIMER_REGISTER->DIER |= TIM_DIER_CC1DE;
IC_TIMER_REGISTER->CCER |= IC_TIMER_CHANNEL;
IC_TIMER_REGISTER->BDTR |= TIM_BDTR_MOE; //输出enable
IC_TIMER_REGISTER->CR1 |= TIM_CR1_CEN;
}
五、ppm解码
void computeServoInput()
{
if (((dma_buffer[1] - dma_buffer[0]) > 800) && ((dma_buffer[1] - dma_buffer[0]) < 2200)) {
if (calibration_required) {
if (!high_calibration_set) {
if (high_calibration_counts == 0) {
last_high_threshold = dma_buffer[1] - dma_buffer[0];
}
high_calibration_counts++;
if (getAbsDif(last_high_threshold, servo_high_threshold) > 50) {
calibration_required = 0;
} else {
servo_high_threshold = ((7 * servo_high_threshold + (dma_buffer[1] - dma_buffer[0])) >> 3);
if (high_calibration_counts > 50) {
servo_high_threshold = servo_high_threshold - 25;
eepromBuffer[33] = (servo_high_threshold - 1750) / 2;
high_calibration_set = 1;
playDefaultTone();
}
}
last_high_threshold = servo_high_threshold;
}
if (high_calibration_set) {
if (dma_buffer[1] - dma_buffer[0] < 1250) {
low_calibration_counts++;
servo_low_threshold = ((7 * servo_low_threshold + (dma_buffer[1] - dma_buffer[0])) >> 3);
}
if (low_calibration_counts > 75) {
servo_low_threshold = servo_low_threshold + 25;
eepromBuffer[32] = (servo_low_threshold - 750) / 2;
calibration_required = 0;
saveEEpromSettings();
low_calibration_counts = 0;
playChangedTone();
}
}
signaltimeout = 0;
} else {
if (bi_direction) {
if (dma_buffer[1] - dma_buffer[0] <= servo_neutral) {
servorawinput = map((dma_buffer[1] - dma_buffer[0]),
servo_low_threshold, servo_neutral, 0, 1000);
} else {
servorawinput = map((dma_buffer[1] - dma_buffer[0]), servo_neutral + 1,
servo_high_threshold, 1001, 2000);
}
} else {
servorawinput = map((dma_buffer[1] - dma_buffer[0]), servo_low_threshold,
servo_high_threshold, 47, 2047);
if (servorawinput <= 48) {
servorawinput = 0;
}
}
signaltimeout = 0;
}
} else {
zero_input_count = 0; // reset if out of range
}
if (servorawinput - newinput > max_servo_deviation) {
newinput += max_servo_deviation;
} else if (newinput - servorawinput > max_servo_deviation) {
newinput -= max_servo_deviation;
} else {
newinput = servorawinput;
}
}
六、dshot解码
void computeDshotDMA()
{
int j = 0;
dshot_frametime = dma_buffer[31] - dma_buffer[0];
halfpulsetime = dshot_frametime >> 5;
if ((dshot_frametime > dshot_frametime_low) && (dshot_frametime < dshot_frametime_high)) {
for (int i = 0; i < 16; i++) {
dpulse[i] = ((dma_buffer[j + (i << 1) + 1] - dma_buffer[j + (i << 1)]) > (halfpulsetime));
}
uint8_t calcCRC = ((dpulse[0] ^ dpulse[4] ^ dpulse[8]) << 3 | (dpulse[1] ^ dpulse[5] ^ dpulse[9]) << 2 | (dpulse[2] ^ dpulse[6] ^ dpulse[10]) << 1 | (dpulse[3] ^ dpulse[7] ^ dpulse[11]));
uint8_t checkCRC = (dpulse[12] << 3 | dpulse[13] << 2 | dpulse[14] << 1 | dpulse[15]);
if (!armed) {
if (dshot_telemetry == 0) {
if (getInputPinState()) { // if the pin is high for 100 checks between
// signal pulses its inverted
high_pin_count++;
if (high_pin_count > 100) {
dshot_telemetry = 1;
}
}
}
}
if (dshot_telemetry) {
checkCRC = ~checkCRC + 16;
}
int tocheck = (dpulse[0] << 10 | dpulse[1] << 9 | dpulse[2] << 8 | dpulse[3] << 7 | dpulse[4] << 6 | dpulse[5] << 5 | dpulse[6] << 4 | dpulse[7] << 3 | dpulse[8] << 2 | dpulse[9] << 1 | dpulse[10]);
if (calcCRC == checkCRC) {
signaltimeout = 0;
dshot_goodcounts++;
if (dpulse[11] == 1) {
send_telemetry = 1;
}
if (tocheck > 47) {
if (EDT_ARMED) {
newinput = tocheck;
dshotcommand = 0;
command_count = 0;
return;
}
}
if ((tocheck <= 47) && (tocheck > 0)) {
newinput = 0;
dshotcommand = tocheck; // todo
}
if (tocheck == 0) {
if (EDT_ARM_ENABLE == 1) {
EDT_ARMED = 0;
}
newinput = 0;
dshotcommand = 0;
command_count = 0;
}
if ((dshotcommand > 0) && (running == 0) && armed) {
if (dshotcommand != last_command) {
last_command = dshotcommand;
command_count = 0;
}
if (dshotcommand < 5) { // beacons
command_count = 6; // go on right away
}
command_count++;
if (command_count >= 6) {
command_count = 0;
switch (dshotcommand) { // todo
case 1:
play_tone_flag = 1;
break;
case 2:
play_tone_flag = 2;
break;
case 3:
play_tone_flag = 3;
break;
case 4:
play_tone_flag = 4;
break;
case 5:
play_tone_flag = 5;
break;
case 7:
dir_reversed = 0;
forward = 1 - dir_reversed;
// play_tone_flag = 1;
break;
case 8:
dir_reversed = 1;
forward = 1 - dir_reversed;
// play_tone_flag = 2;
break;
case 9:
bi_direction = 0;
break;
case 10:
bi_direction = 1;
break;
case 12:
saveEEpromSettings();
play_tone_flag = 1 + dir_reversed;
// NVIC_SystemReset();
break;
case 13:
dshot_extended_telemetry = 1;
send_extended_dshot = 0b111000000000;
if (EDT_ARM_ENABLE == 1) {
EDT_ARMED = 1;
}
break;
case 14:
dshot_extended_telemetry = 0;
send_extended_dshot = 0b111011111111;
// make_dshot_package();
break;
case 20:
forward = 1 - dir_reversed;
break;
case 21:
forward = dir_reversed;
break;
}
last_dshot_command = dshotcommand;
dshotcommand = 0;
}
}
} else {
dshot_badcounts++;
}
}
}
stm32定时器学习
- 定时器复位
RCC->APBRSTR1 |= LL_APB1_GRP1_PERIPH_TIM3;
RCC->APBRSTR1 &= ~LL_APB1_GRP1_PERIPH_TIM3;
- ppm 信号,每个脉宽是0.5ms (15us — 1500us)
- dshot信号
dshot600: frq: 600k 周期: 1s/600k = 1667ns T0h=625ns T1h=1250ns
dshot100: 1s/100k=10000ns
dshot300: 1s/300k = 3300ns
dshot1200: 1s/1200k = 832ns