Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added DSHOT and MULTI PWM #5

Merged
merged 2 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 21 additions & 112 deletions common/Varmint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,22 +390,34 @@ float Varmint::rc_read(uint8_t chan)
ever_read = true;
}

if ((chan < PWM_CHANNELS) & ever_read)
if ((chan < RC_PACKET_CHANNELS) & ever_read)
return p.chan[chan];
return -1; // out of range or no data in p
}

///////////////////////////////////////////////////////////////////////////////////////////////
// PWM

// legacy, all channels are pwm and set to the same 'refresh_rate'
void Varmint::pwm_init(uint32_t refresh_rate, uint16_t idle_pwm)
{
for (int ch = 0; ch < PWM_CHANNELS; ch++)
pwm_.disable(ch);
for (int ch = 0; ch < PWM_CHANNELS; ch++)
pwm_.set_rate(ch, refresh_rate);
{
pwm_.setRate(ch, refresh_rate);
if(idle_pwm==0) pwm_.writeUs(ch, 0); // OFF
else pwm_.write(ch, 0.0); // Channel minimum value
}
for (int ch = 0; ch < PWM_CHANNELS; ch++)
pwm_.enable(ch);
}

void Varmint::pwm_init_multi(const float *rate, uint32_t channels)
{
pwm_.updateConfig(rate,channels);
}

void Varmint::pwm_disable(void)
{
for (int ch = 0; ch < PWM_CHANNELS; ch++)
Expand All @@ -416,6 +428,13 @@ void Varmint::pwm_write(uint8_t ch, float value)
pwm_.write(ch, value);
}

void Varmint::pwm_write_multi(float *value, uint32_t channels)
{
pwm_.write(value, channels);
}



///////////////////////////////////////////////////////////////////////////////////////////////
// LEDs
void Varmint::led0_on() // Red LED
Expand Down Expand Up @@ -491,113 +510,3 @@ bool Varmint::memory_write(const void *src, size_t len)

///////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions (not part of parent class)

//uint32_t Varmint::pwm_init_timers(uint32_t servo_pwm_period_us)
//{
// {
// TIM_MasterConfigTypeDef sMasterConfig = {0};
// TIM_OC_InitTypeDef sConfigOC = {0};
// TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
//
// htim1.Instance = TIM1;
// htim1.Init.Prescaler = (SERVO_PWM_CLK_DIV);
// htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
// htim1.Init.Period = servo_pwm_period_us;
// htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// htim1.Init.RepetitionCounter = 0;
// htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
// if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
// sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
// sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
// if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sConfigOC.OCMode = TIM_OCMODE_PWM1;
// sConfigOC.Pulse = (SERVO_PWM_CENTER);
// sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
// sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
// sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
// sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
// sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
// if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
// sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
// sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
// sBreakDeadTimeConfig.DeadTime = 0;
// sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
// sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
// sBreakDeadTimeConfig.BreakFilter = 0;
// sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
// sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
// sBreakDeadTimeConfig.Break2Filter = 0;
// sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
// if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
// return DRIVER_HAL_ERROR;
// HAL_TIM_MspPostInit(&htim1);
// }
//#if defined(htim3)
// {
// TIM_MasterConfigTypeDef sMasterConfig = {0};
// TIM_OC_InitTypeDef sConfigOC = {0};
// htim3.Instance = TIM3;
// htim3.Init.Prescaler = (SERVO_PWM_CLK_DIV);
// htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
// htim3.Init.Period = servo_pwm_period_us;
// htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
// if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
// sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
// if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sConfigOC.OCMode = TIM_OCMODE_PWM1;
// sConfigOC.Pulse = (SERVO_PWM_CENTER);
// sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
// sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
// if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
// return DRIVER_HAL_ERROR;
// HAL_TIM_MspPostInit(&htim3);
// }
//#endif
// {
// TIM_MasterConfigTypeDef sMasterConfig = {0};
// TIM_OC_InitTypeDef sConfigOC = {0};
// htim4.Instance = TIM4;
// htim4.Init.Prescaler = (SERVO_PWM_CLK_DIV);
// htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
// htim4.Init.Period = servo_pwm_period_us;
// htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
// if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
// sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
// if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
// return DRIVER_HAL_ERROR;
// sConfigOC.OCMode = TIM_OCMODE_PWM1;
// sConfigOC.Pulse = (SERVO_PWM_CENTER);
// sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
// sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
// if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
// return DRIVER_HAL_ERROR;
// if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
// return DRIVER_HAL_ERROR;
// HAL_TIM_MspPostInit(&htim4);
// }
// return DRIVER_OK;
//}
3 changes: 1 addition & 2 deletions common/drivers/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
class Driver
{
public:
// virtual bool startDma (void)=0; // Called in response to a data ready signal
// virtual void endDma (void)=0; // Called when DMA read is complete

virtual bool display(void) = 0;

uint16_t rxFifoCount(void)
Expand Down
128 changes: 76 additions & 52 deletions common/drivers/Pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,82 @@
// 600 600kbit/s 1.25 0.625 1.67 26.72
// 1200 1200kbit/s 0.625 0.313 0.83 13.28

typedef enum
{
PWM_STD,
PWM_DSHOT,
} PwmProtocol;

//typedef struct __attribute__((__packed__))
//{
// TIM_HandleTypeDef *htim;
// uint16_t channel;
// uint16_t min;
// uint16_t center;
// uint16_t max;
//} PwmChannelCfg;

typedef struct __attribute__((__packed__))
__attribute__((section(".data"))) PwmBlockStructure pwm_init[PWM_TIMER_BLOCKS] = PWM_INIT_DEFINE;

__attribute__((section("my_dma_buffers")))
__attribute__((aligned(32))) static uint32_t pwm_dma_buf[PWM_TIMER_BLOCKS][PWM_DMA_BUFFER_LEN] = {0};


void Pwm::updateConfig(const float *rate, uint32_t channels)
{
TIM_TypeDef *instance;
PwmProtocol protocol;
uint32_t period_counts;
} PwmBlockCfg;
channels = (channels<PWM_CHANNELS)?channels:PWM_CHANNELS;

__attribute__((section(".data"))) PwmChannelCfg pwm_ch[PWM_CHANNELS] = PWM_CHANNELS_DEFINE;
__attribute__((section(".data"))) PwmBlockCfg pwm_blk[PWM_BLOCKS] = PWM_BLOCKS_DEFINE;
for(uint32_t ch=0;ch<channels;ch++)
HAL_TIM_PWM_Stop(htim_[ch], chan_[ch]);

for(uint32_t ch=0;ch<channels;ch++)
setRate(ch,rate[ch]);

for(uint32_t ch=0;ch<channels;ch++)
HAL_TIM_PWM_Start(htim_[ch], chan_[ch]);
}

//#define PWM_CLOCK (2e8) // 200 MHz

uint32_t Pwm::init(void)
{
chan_ = pwm_ch;
for(uint8_t bk=0;bk<PWM_BLOCKS;bk++)
block_ = pwm_init;
dmaBuf_ = pwm_dma_buf;

// Clear lookup table
for(uint32_t output_index = 0; output_index<PWM_CHANNELS; output_index++)
{
htim_[output_index] = nullptr;
chan_[output_index] = PWM_CHAN_IGNORE;
blockIndex_[output_index] = (uint32_t)(-1);
}

// Fill-in lookup tables
for(uint32_t bk=0;bk<PWM_TIMER_BLOCKS;bk++)
{
TIM_HandleTypeDef *htim;
if(pwm_blk[bk].instance==TIM1) htim = &htim1;
else if(pwm_blk[bk].instance==TIM3) htim = &htim3;
else if(pwm_blk[bk].instance==TIM4) htim = &htim4;
else if(pwm_blk[bk].instance==TIM8) htim = &htim8;

uint32_t prescaler; // yields 1us per count with a 200MHz clock input
if(pwm_blk[bk].protocol==PWM_DSHOT)
prescaler = 0; // 5ns per count.
else // PWM_STD
prescaler = 199; // 1us per count

TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

htim->Instance = pwm_blk[bk].instance;
htim->Init.Prescaler = prescaler;
for( uint32_t ch=0; ch<4; ch++)
{
uint32_t output_index = block_[bk].chan[ch];
if( output_index<PWM_CHANNELS )
{
blockIndex_[output_index] = bk;
htim_[output_index] = block_[bk].htim;
chan_[output_index] = (uint32_t)ch<<2; // Note: TIM_CHANNEL_x = (x-1)*4; up to x==4
}
}
}

for(uint32_t bk=0;bk<PWM_TIMER_BLOCKS;bk++)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

TIM_HandleTypeDef *htim = block_[bk].htim;

if(htim == &htim1) htim->Instance = TIM1;
else if(htim == &htim3) htim->Instance = TIM3;
else if(htim == &htim4) htim->Instance = TIM4;
else if(htim == &htim8) htim->Instance = TIM8;
else return DRIVER_HAL_ERROR;

if((block_[bk].rate >= 150000) && (block_[bk].type == PWM_DSHOT)) // DSHOT
{
htim->Init.Prescaler = 0;
htim->Init.Period = (uint64_t)200000000/block_[bk].rate;
}
else if((block_[bk].type == PWM_STANDARD) && (block_[bk].rate < 490))
{
htim->Init.Prescaler = 199;
htim->Init.Period = (uint64_t)1000000/block_[bk].rate;
}
else
return DRIVER_HAL_ERROR;

htim->Init.CounterMode = TIM_COUNTERMODE_UP;
htim->Init.Period = pwm_blk[bk].period_counts;
htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim->Init.RepetitionCounter = 0;
htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
Expand All @@ -108,24 +133,24 @@ uint32_t Pwm::init(void)
if (HAL_TIMEx_MasterConfigSynchronization(htim, &sMasterConfig) != HAL_OK)
return DRIVER_HAL_ERROR;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
// sConfigOC.Pulse = (SERVO_PWM_CENTER);
// sConfigOC.Pulse = 1500;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;

for(uint8_t ch=0;ch<PWM_CHANNELS;ch++)
for(uint32_t ch=0;ch<4;ch++)
{
if(pwm_ch[ch].htim==htim)
if(block_[bk].chan[ch]<PWM_CHANNELS)
{
sConfigOC.Pulse = pwm_ch[ch].center;
if (HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, pwm_ch[ch].channel) != HAL_OK)
sConfigOC.Pulse = 0; // default to flat line output
if (HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC,(uint32_t)ch*4) != HAL_OK)
return DRIVER_HAL_ERROR;
}
}

if( (pwm_blk[bk].instance==TIM1) || (pwm_blk[bk].instance==TIM8))
if( (htim==&htim1) || (htim==&htim8))
{
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
Expand All @@ -142,9 +167,8 @@ uint32_t Pwm::init(void)
if (HAL_TIMEx_ConfigBreakDeadTime(htim, &sBreakDeadTimeConfig) != HAL_OK)
return DRIVER_HAL_ERROR;
}

HAL_TIM_MspPostInit(htim);

HAL_TIM_MspPostInit(htim);
}

return DRIVER_OK;
}
Loading
Loading