diff --git a/lib/mruby b/lib/mruby index 850ed00..61d8f29 160000 --- a/lib/mruby +++ b/lib/mruby @@ -1 +1 @@ -Subproject commit 850ed007ae5f457ff97989813452e75fce33f833 +Subproject commit 61d8f2914591b092064635fc06e3b3e1bc0275cf diff --git a/src/mrb_machine_impl/mrb_machine_pwm_impl.c b/src/mrb_machine_impl/mrb_machine_pwm_impl.c index 99641c4..d65a74f 100644 --- a/src/mrb_machine_impl/mrb_machine_pwm_impl.c +++ b/src/mrb_machine_impl/mrb_machine_pwm_impl.c @@ -26,6 +26,9 @@ /* FIXME: A reasonable clock for PWM resolution, could be determined dynamically. */ #define PWM_IMPL_REASONABLE_CLK (10000000UL) /* 10MHz */ +#define PWM_IMPL_MR_RL_MASK \ + (CTIMER_MCR_MR0RL_MASK | CTIMER_MCR_MR1RL_MASK | CTIMER_MCR_MR2RL_MASK | CTIMER_MCR_MR3RL_MASK) + /* Timer channel ID fields */ #define PWM_IMPL_CT_OFFSET_Pos 0 @@ -34,7 +37,7 @@ #define PWM_IMPL_CT_CH_Pos 1 #define PWM_IMPL_CT_CH_Msk (3U << PWM_IMPL_CT_CH_Pos) -#define PWM_IMPL_CT_INST_Pos 4 +#define PWM_IMPL_CT_INST_Pos 3 #define PWM_IMPL_CT_INST_Msk (0x1FU << PWM_IMPL_CT_INST_Pos) #define PWM_IMPL_CT_OFFSET(x) ((x & PWM_IMPL_CT_OFFSET_Msk) >> PWM_IMPL_CT_OFFSET_Pos) @@ -64,7 +67,7 @@ (((port << PWM_IMPL_PIN_PORT_Pos) & PWM_IMPL_PIN_PORT_Msk) | ((id << PWM_IMPL_PIN_ID_Pos) & PWM_IMPL_PIN_ID_Msk) | \ ((func << PWM_IMPL_PIN_FUNC_Pos) & PWM_IMPL_PIN_FUNC_Msk) | PWM_IMPL_PIN_VALID_Msk) -static uint32_t const s_pwm_channel_map[PWM_IMPL_INST_COUNT][PWM_IMPL_INST_COUNT * 2] = { +static uint32_t const s_pwm_channel_map[PWM_IMPL_INST_COUNT][PWM_IMPL_INST_CH * 2] = { { 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 @@ -106,7 +109,10 @@ static CTIMER_Type *const s_pwm_ct_list[] = { }; static IRQn_Type const s_pwm_irq_list[] = { - CTIMER0_IRQn, CTIMER1_IRQn, CTIMER2_IRQn, CTIMER3_IRQn, + CTIMER0_IRQn, + CTIMER1_IRQn, + CTIMER2_IRQn, + CTIMER3_IRQn, }; static bool mrb_machine_pwm_ctimer_in_use(uint8_t ctimer_id) { @@ -154,7 +160,7 @@ int mrb_machine_pwm_impl_init(uint32_t channel, machine_pwm_config_t *config) { return -1; } - uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_off]; + uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_mat * 2 + ctimer_off]; CTIMER_Type *ctimer_inst = s_pwm_ct_list[ctimer_id]; /* Check valid bit to see if there really is a pin for this channel */ @@ -178,27 +184,42 @@ int mrb_machine_pwm_impl_init(uint32_t channel, machine_pwm_config_t *config) { CTIMER_Init(ctimer_inst, &ct_cfg); CTIMER_EnableResetMatchChannel(ctimer_inst, kCTIMER_Match_3, true); - } - /* From now on, the pin will be controlled by MATx PWM */ - ctimer_inst->PWMC |= (1 << ctimer_mat); + ctimer_inst->MR[3] = 0x00000000UL; + ctimer_inst->MCR |= (CTIMER_MCR_MR3RL_MASK); + + CTIMER_StartTimer(ctimer_inst); + } /* Calculate new reload value */ uint32_t rl_match_old = ctimer_inst->MR[3]; uint32_t rl_match_new = (PWM_IMPL_REASONABLE_CLK / config->freq); + uint32_t ch_enabled = ctimer_inst->MCR & PWM_IMPL_MR_RL_MASK; + + /* Do not sync channels while we are fiddling with shadow registers */ + ctimer_inst->MCR &= ~(PWM_IMPL_MR_RL_MASK); + + /* Update period channel */ ctimer_inst->MSR[3] = rl_match_new; + /* To disable PWM output: Write MRx to 0xFFFFFFFF, to enable, enable reload from shadow. */ + for (uint8_t i = 0; i < 3; i++) { if (ctimer_inst->PWMC & (1 << i)) { - /* Corresponding PWM channel is enabled */ - uint32_t new_duty = (((uint64_t)ctimer_inst->MR[i] * rl_match_new) / rl_match_old); + uint32_t new_duty = (uint32_t)((uint64_t)ctimer_inst->MSR[i] * rl_match_new / rl_match_old); ctimer_inst->MSR[i] = new_duty; } } - /* To disable PWM output: Write MRx to 0xFFFFFFFF, to enable, enable reload from shadow. */ - /* Since PWMC is enabled, no action will be performed on MRx registers */ + /* New channel */ + ctimer_inst->MSR[ctimer_mat] = rl_match_new - ((config->duty * rl_match_new) / 65536); + + /* Start sync MRx values with shadow registers */ + ctimer_inst->MCR |= ch_enabled | (1U << (CTIMER_MCR_MR0RL_SHIFT + ctimer_mat)); + + /* From now on, the pin will be controlled by MATx PWM */ + ctimer_inst->PWMC |= (1 << ctimer_mat); /* Function is retrieved from const array. */ uint32_t iocon_mode = IOCON_PIO_SLEW(0) | IOCON_DIGITAL_EN | IOCON_PIO_FUNC(PWM_IMPL_PIN_FUNC(ctimer_pin)); @@ -208,3 +229,101 @@ int mrb_machine_pwm_impl_init(uint32_t channel, machine_pwm_config_t *config) { return 0; } + +int mrb_machine_pwm_impl_output_set(uint32_t channel, bool enable) { + uint8_t ctimer_id = PWM_IMPL_CT_INST(channel); + uint8_t ctimer_mat = PWM_IMPL_CT_CH(channel); + uint8_t ctimer_off = PWM_IMPL_CT_OFFSET(channel); + + /* Sanity checks */ + if ((ctimer_id >= PWM_IMPL_INST_COUNT) || (ctimer_mat >= PWM_IMPL_INST_CH)) { + return -1; + } + + uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_mat * 2 + ctimer_off]; + CTIMER_Type *ctimer_inst = s_pwm_ct_list[ctimer_id]; + + /* Check valid bit to see if there really is a pin for this channel */ + if (PWM_IMPL_PIN_VALID(ctimer_pin) == 0) { + return -2; + } + + if (enable) { + ctimer_inst->MCR |= (1 << (CTIMER_MCR_MR0RL_SHIFT + ctimer_mat)); + } else { + ctimer_inst->MCR &= ~(1 << (CTIMER_MCR_MR0RL_SHIFT + ctimer_mat)); + ctimer_inst->MR[ctimer_mat] = 0xFFFFFFFFUL; + } + + return 0; +} + +bool mrb_machine_pwm_impl_output_get(uint32_t channel) { + uint8_t ctimer_id = PWM_IMPL_CT_INST(channel); + uint8_t ctimer_mat = PWM_IMPL_CT_CH(channel); + uint8_t ctimer_off = PWM_IMPL_CT_OFFSET(channel); + + /* Sanity checks */ + if ((ctimer_id >= PWM_IMPL_INST_COUNT) || (ctimer_mat >= PWM_IMPL_INST_CH)) { + return false; + } + + uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_off]; + CTIMER_Type *ctimer_inst = s_pwm_ct_list[ctimer_id]; + + /* Check valid bit to see if there really is a pin for this channel */ + if (PWM_IMPL_PIN_VALID(ctimer_pin) == 0) { + return false; + } + + if (ctimer_inst->MCR & (1 << (CTIMER_MCR_MR0RL_SHIFT + ctimer_mat))) { + return true; + } else { + return false; + } +} + +int mrb_machine_pwm_impl_duty_set(uint32_t channel, uint16_t duty) { + uint8_t ctimer_id = PWM_IMPL_CT_INST(channel); + uint8_t ctimer_mat = PWM_IMPL_CT_CH(channel); + uint8_t ctimer_off = PWM_IMPL_CT_OFFSET(channel); + + /* Sanity checks */ + if ((ctimer_id >= PWM_IMPL_INST_COUNT) || (ctimer_mat >= PWM_IMPL_INST_CH)) { + return -1; + } + + uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_off]; + CTIMER_Type *ctimer_inst = s_pwm_ct_list[ctimer_id]; + + /* Check valid bit to see if there really is a pin for this channel */ + if (PWM_IMPL_PIN_VALID(ctimer_pin) == 0) { + return -2; + } + + ctimer_inst->MSR[ctimer_mat] = ctimer_inst->MSR[3] - ((uint32_t)duty * ctimer_inst->MSR[3] / 65536); + + return 0; +} +uint16_t mrb_machine_pwm_impl_duty_get(uint32_t channel) { + uint8_t ctimer_id = PWM_IMPL_CT_INST(channel); + uint8_t ctimer_mat = PWM_IMPL_CT_CH(channel); + uint8_t ctimer_off = PWM_IMPL_CT_OFFSET(channel); + + /* Sanity checks */ + if ((ctimer_id >= PWM_IMPL_INST_COUNT) || (ctimer_mat >= PWM_IMPL_INST_CH)) { + return 0; + } + + uint32_t ctimer_pin = s_pwm_channel_map[ctimer_id][ctimer_off]; + CTIMER_Type *ctimer_inst = s_pwm_ct_list[ctimer_id]; + + /* Check valid bit to see if there really is a pin for this channel */ + if (PWM_IMPL_PIN_VALID(ctimer_pin) == 0) { + return 0; + } + + uint16_t duty = ctimer_inst->MSR[ctimer_mat] * 65536 / ctimer_inst->MSR[3]; + + return duty; +} \ No newline at end of file