Added some PWM API (WIP).

Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
Yilin Sun 2023-03-28 08:52:16 +08:00
parent 5c3e2a0640
commit e024eb97d4
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
2 changed files with 39 additions and 21 deletions

@ -1 +1 @@
Subproject commit 7b84e47e26ce6d180057b5c303ba21ac9e92ee9a
Subproject commit 850ed007ae5f457ff97989813452e75fce33f833

View File

@ -16,15 +16,16 @@
* LPC55S69 has 5 CTimers, each with 4 Match channels, each channel can route up to 2 pins
* Total: 40 PWM capable pins (at most)
* Actual: 30 pins (shared).
* Match channel 3 is special, normally it will be used as period channel, until
* initialized explicitly.
* The match channel will be switched to channel 2 if 3 is initialized, or to 1 if channel 2 is initialized
* eventually to 0. If all channels are occupied, then channel 3 can not be initialized.
* Match channel 3 is special, normally it will be used as period channel
* TODO: Find a way to utilize channel 3 as normal PWM outputs
*/
#define PWM_IMPL_INST_COUNT 5
#define PWM_IMPL_INST_CH 4
/* FIXME: A reasonable clock for PWM resolution, could be determined dynamically. */
#define PWM_IMPL_REASONABLE_CLK (10000000UL)
/* Timer channel ID fields */
#define PWM_IMPL_CT_OFFSET_Pos 0
@ -68,25 +69,25 @@ static const uint32_t s_pwm_channel_map[PWM_IMPL_INST_COUNT][PWM_IMPL_INST_COUNT
PWM_IMPL_PIN(0, 0, 3), PWM_IMPL_PIN(0, 30, 3), // CT0MAT0, Channel ID: 0, 1
PWM_IMPL_PIN(0, 3, 2), PWM_IMPL_PIN(0, 31, 3), // CT0MAT1, Channel ID: 2, 3
PWM_IMPL_PIN(0, 19, 3), PWM_IMPL_PIN(1, 31, 3), // CT0MAT2, Channel ID: 4, 5
PWM_IMPL_PIN(1, 2, 3), PWM_IMPL_PIN(1, 27, 3), // CT0MAT3, Channel ID: 6, 7
0x00000000UL, 0x00000000UL, // CT0MAT3, Channel ID: 6, 7
},
{
PWM_IMPL_PIN(0, 18, 3), PWM_IMPL_PIN(1, 10, 3), // CT1MAT0, Channel ID: 8, 9
PWM_IMPL_PIN(0, 20, 2), PWM_IMPL_PIN(1, 12, 3), // CT1MAT1, Channel ID: 10, 11
PWM_IMPL_PIN(0, 23, 2), PWM_IMPL_PIN(1, 14, 3), // CT1MAT2, Channel ID: 12, 13
PWM_IMPL_PIN(1, 16, 3), 0x00000000UL, // CT1MAT3, Channel ID: 14, 15
0x00000000UL, 0x00000000UL, // CT1MAT3, Channel ID: 14, 15
},
{
PWM_IMPL_PIN(0, 10, 3), PWM_IMPL_PIN(1, 5, 3), // CT2MAT0, Channel ID: 16, 17
PWM_IMPL_PIN(1, 4, 3), PWM_IMPL_PIN(1, 6, 3), // CT2MAT1, Channel ID: 18, 19
PWM_IMPL_PIN(0, 11, 2), PWM_IMPL_PIN(1, 7, 3), // CT2MAT2, Channel ID: 20, 21
PWM_IMPL_PIN(0, 29, 3), PWM_IMPL_PIN(1, 22, 3), // CT2MAT3, Channel ID: 22, 23
PWM_IMPL_PIN(0, 10, 3), PWM_IMPL_PIN(1, 5, 3), // CT2MAT0, Channel ID: 16, 17
PWM_IMPL_PIN(1, 4, 3), PWM_IMPL_PIN(1, 6, 3), // CT2MAT1, Channel ID: 18, 19
PWM_IMPL_PIN(0, 11, 2), PWM_IMPL_PIN(1, 7, 3), // CT2MAT2, Channel ID: 20, 21
0x00000000UL, 0x00000000UL, // CT2MAT3, Channel ID: 22, 23
},
{
PWM_IMPL_PIN(0, 5, 3), 0x00000000UL, // CT3MAT0, Channel ID: 24, 25
PWM_IMPL_PIN(1, 19, 3), 0x00000000UL, // CT3MAT1, Channel ID: 26, 27
PWM_IMPL_PIN(0, 27, 3), PWM_IMPL_PIN(1, 21, 3), // CT3MAT2, Channel ID: 28, 29
PWM_IMPL_PIN(1, 22, 3), PWM_IMPL_PIN(1, 27, 3), // CT3MAT3, Channel ID: 30, 31
0x00000000UL, 0x00000000UL, // CT3MAT3, Channel ID: 30, 31
},
{
PWM_IMPL_PIN(0, 6, 3), 0x00000000UL, // CT4MAT0, Channel ID: 32, 33
@ -96,11 +97,11 @@ static const uint32_t s_pwm_channel_map[PWM_IMPL_INST_COUNT][PWM_IMPL_INST_COUNT
},
};
static const clock_attach_id_t s_pwm_clk_attach_list[] = {
static clock_attach_id_t const s_pwm_clk_attach_list[] = {
kMAIN_CLK_to_CTIMER0, kMAIN_CLK_to_CTIMER1, kMAIN_CLK_to_CTIMER2, kMAIN_CLK_to_CTIMER3, kMAIN_CLK_to_CTIMER4,
};
static const CTIMER_Type *s_pwm_ct_list[] = {
static CTIMER_Type * const s_pwm_ct_list[] = {
CTIMER0, CTIMER1, CTIMER2, CTIMER3, CTIMER4,
};
@ -120,17 +121,23 @@ static bool mrb_machine_pwm_ctimer_in_use(uint8_t ctimer_id) {
}
/* Check if this CTIMER is enabled */
if((ct_inst->TCR & CTIMER_TCR_CEN_MASK) == 0) {
if ((ct_inst->TCR & CTIMER_TCR_CEN_MASK) == 0) {
return false;
}
/* Check if any MATCH channels are configured as reset.
* For a typical PWM setup, a channel needs at least 1 MATCH channel set as reset */
if((ct_inst->MCR & (CTIMER_MCR_MR0R_MASK | CTIMER_MCR_MR1R_MASK | CTIMER_MCR_MR2R_MASK | CTIMER_MCR_MR3R_MASK)) == 0) {
/* Check if Match channel 3 is configured as reset. */
/* TODO: Find a way to utilize channel 3 as normal PWM outputs */
if ((ct_inst->MCR & CTIMER_MCR_MR3R_MASK) == 0) {
return false;
}
/* Check if any PWM outputs are enabled */
/* TODO: Find a way to utilize channel 3 as normal PWM outputs */
if ((ct_inst->PWMC & (CTIMER_PWMC_PWMEN0_MASK | CTIMER_PWMC_PWMEN1_MASK | CTIMER_PWMC_PWMEN2_MASK)) == 0) {
return false;
}
return true;
}
int mrb_machine_pwm_impl_init(uint32_t channel, machine_pwm_config_t *config) {
@ -150,8 +157,19 @@ int mrb_machine_pwm_impl_init(uint32_t channel, machine_pwm_config_t *config) {
return -2;
}
/* FIXME: Check CTIMER status and match channel status before setting pin mode */
/* TODO: Set up CTIMER if not configured previously */
if(!mrb_machine_pwm_ctimer_in_use(ctimer_id)) {
/* CTimer is not in use, initialize timer */
CLOCK_AttachClk(s_pwm_clk_attach_list[ctimer_id]);
ctimer_config_t ct_cfg;
CTIMER_GetDefaultConfig(&ct_cfg);
ct_cfg.prescale = CLOCK_GetCTimerClkFreq(ctimer_id) / PWM_IMPL_REASONABLE_CLK;
CTIMER_Init(s_pwm_ct_list[ctimer_id], &ct_cfg);
}
/* FIXME: How to determine whether CTIMER is set up previously? Tips: CTIMER might be used by other gems... */
/* Function is retrieved from const array. */