imxrt:io_timers Support 1 channel per group (timer)

This commit is contained in:
David Sidrane 2022-10-12 00:26:41 -07:00 committed by Beat Küng
parent 7f7137320a
commit 3be8d52c8e
3 changed files with 109 additions and 55 deletions

View File

@ -45,7 +45,11 @@
#pragma once
__BEGIN_DECLS
/* configuration limits */
#define MAX_IO_TIMERS 4
#ifdef BOARD_NUM_IO_TIMERS
#define MAX_IO_TIMERS BOARD_NUM_IO_TIMERS
#else
#define MAX_IO_TIMERS 4
#endif
#define MAX_TIMER_IO_CHANNELS 16
#define MAX_LED_TIMERS 2
@ -78,6 +82,7 @@ typedef uint16_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_
*/
typedef struct io_timers_t {
uint32_t base; /* Base address of the timer */
uint32_t submodle; /* Which Submodule */
uint32_t clock_register; /* SIM_SCGCn */
uint32_t clock_bit; /* SIM_SCGCn bit pos */
uint32_t vectorno; /* IRQ number */

View File

@ -56,7 +56,6 @@ static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t
PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad)
{
timer_io_channels_t ret{};
PWM::FlexPWM pwm{};
// FlexPWM Muxing Options
@ -591,7 +590,7 @@ static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t
const uint32_t timer_base = getFlexPWMBaseRegister(pwm);
for (int i = 0; i < MAX_IO_TIMERS; ++i) {
if (io_timers_conf[i].base == timer_base) {
if (io_timers_conf[i].base == timer_base && io_timers_conf[i].submodle == ret.sub_module) {
ret.timer_index = i;
break;
}
@ -602,11 +601,11 @@ static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t
return ret;
}
static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm)
static inline constexpr io_timers_t initIOPWM(PWM::FlexPWM pwm, PWM::FlexPWMSubmodule sub)
{
io_timers_t ret{};
ret.base = getFlexPWMBaseRegister(pwm);
ret.submodle = sub;
return ret;
}

View File

@ -431,46 +431,69 @@ static inline void io_timer_set_PWM_mode(unsigned channel)
void io_timer_trigger(unsigned channel_mask)
{
// Any Channels in oneshot?
int oneshots = io_timer_get_mode_channels(IOTimerChanMode_OneShot) & channel_mask;
struct {
uint32_t base;
uint16_t triggers;
} action_cache[MAX_IO_TIMERS] = {0};
int actions = 0;
/* Pre-calculate the list of channels to Trigger */
int mask;
// Yes do triggering
if (oneshots) {
struct {
uint32_t base;
uint16_t triggers;
} action_cache[MAX_IO_TIMERS] = {0};
for (int timer = 0; timer < MAX_IO_TIMERS; timer++) {
action_cache[actions].base = io_timers[timer].base;
int actions = 0;
if (action_cache[actions].base) {
uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index;
uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count;
// Get the Timer modules addresses
for (int timer = 0; timer < MAX_IO_TIMERS && io_timers[timer].base != 0; timer++) {
if (action_cache[actions].base == 0) {
action_cache[actions].base = io_timers[timer].base;
} else if (action_cache[actions].base != io_timers[timer].base) {
actions++;
action_cache[actions].base = io_timers[timer].base;
}
}
/* Pre-calculate the list of channels to Trigger for each Timer module */
int mask;
uint32_t channel = 0;
for (actions = 0; actions < MAX_IO_TIMERS; actions++) {
if (action_cache[actions].base == 0) {
// All have been processed
break;
}
// Group the bits from channels on the same timer
for (; channel < MAX_TIMER_IO_CHANNELS && timer_io_channels[channel].val_offset; channel++) {
if (io_timers[timer_io_channels[channel].timer_index].base != action_cache[actions].base) {
break;
}
for (uint32_t channel = first_channel_index; channel < last_channel_index; channel++) {
mask = get_channel_mask(channel);
if (oneshots & mask) {
action_cache[actions].triggers |= timer_io_channels[channel].sub_module_bits;
}
}
actions++;
}
/* Now do them all with the shortest delay in between */
irqstate_t flags = px4_enter_critical_section();
for (actions = 0; action_cache[actions].base != 0 && actions < MAX_IO_TIMERS; actions++) {
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= (action_cache[actions].triggers >> MCTRL_LDOK_SHIFT)
<< MCTRL_CLDOK_SHIFT ;
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= action_cache[actions].triggers;
}
px4_leave_critical_section(flags);
}
/* Now do them all with the shortest delay in between */
irqstate_t flags = px4_enter_critical_section();
for (actions = 0; action_cache[actions].base != 0 && actions < MAX_IO_TIMERS; actions++) {
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= (action_cache[actions].triggers >> MCTRL_LDOK_SHIFT)
<< MCTRL_CLDOK_SHIFT ;
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) |= action_cache[actions].triggers;
}
px4_leave_critical_section(flags);
}
int io_timer_init_timer(unsigned timer, io_timer_channel_mode_t mode)
@ -685,44 +708,71 @@ int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_chann
}
struct {
uint32_t sm_ens;
uint32_t base;
uint32_t io_index;
uint32_t gpios[MAX_TIMER_IO_CHANNELS];
} action_cache[MAX_IO_TIMERS];
if (masks) {
struct {
uint32_t sm_ens;
uint32_t base;
uint32_t io_index;
uint32_t gpios[MAX_TIMER_IO_CHANNELS];
} action_cache[MAX_IO_TIMERS];
memset(action_cache, 0, sizeof(action_cache));
unsigned int actions = 0;
memset(action_cache, 0, sizeof(action_cache));
for (int chan_index = 0; masks != 0 && chan_index < MAX_TIMER_IO_CHANNELS; chan_index++) {
if (masks & (1 << chan_index)) {
masks &= ~(1 << chan_index);
for (int timer = 0; timer < MAX_IO_TIMERS && io_timers[timer].base != 0; timer++) {
if (action_cache[actions].base == 0) {
action_cache[actions].base = io_timers[timer].base;
if (io_timer_validate_channel_index(chan_index) == 0) {
uint32_t timer_index = channels_timer(chan_index);
action_cache[timer_index].base = io_timers[timer_index].base;
action_cache[timer_index].sm_ens |= MCTRL_RUN(1 << timer_io_channels[chan_index].sub_module) |
timer_io_channels[chan_index].sub_module_bits;
action_cache[timer_index].gpios[action_cache[timer_index].io_index++] = timer_io_channels[chan_index].gpio_out;
} else if (action_cache[actions].base != io_timers[timer].base) {
actions++;
action_cache[actions].base = io_timers[timer].base;
}
}
}
irqstate_t flags = px4_enter_critical_section();
int chan_index = 0;
for (actions = 0; actions < MAX_IO_TIMERS; actions++) {
if (action_cache[actions].base == 0) {
// All have been processed
break;
}
for (; masks != 0 && chan_index < MAX_TIMER_IO_CHANNELS && timer_io_channels[chan_index].val_offset; chan_index++) {
if (masks & (1 << chan_index)) {
if (io_timers[timer_io_channels[chan_index].timer_index].base != action_cache[actions].base) {
break;
}
masks &= ~(1 << chan_index);
action_cache[actions].sm_ens |= MCTRL_RUN(1 << timer_io_channels[chan_index].sub_module) |
timer_io_channels[chan_index].sub_module_bits;
action_cache[actions].gpios[action_cache[actions].io_index++] = timer_io_channels[chan_index].gpio_out;
}
}
}
irqstate_t flags = px4_enter_critical_section();
for (actions = 0; actions < arraySize(action_cache); actions++) {
if (action_cache[actions].base == 0) {
break;
}
for (unsigned actions = 0; actions < arraySize(action_cache); actions++) {
if (action_cache[actions].base != 0) {
for (unsigned int index = 0; index < action_cache[actions].io_index; index++) {
if (action_cache[actions].gpios[index]) {
px4_arch_configgpio(action_cache[actions].gpios[index]);
}
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) = action_cache[actions].sm_ens;
}
_REG16(action_cache[actions].base, IMXRT_FLEXPWM_MCTRL_OFFSET) = action_cache[actions].sm_ens;
}
px4_leave_critical_section(flags);
}
px4_leave_critical_section(flags);
return 0;
}