/****************************************************************************** * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. * ******************************************************************************/ /* **** Includes **** */ #include <stddef.h> #include "mxc_assert.h" #include "tmr.h" #include "tmr_revb.h" #include "gpio.h" #include "mxc_pins.h" #include "mxc_lock.h" /* **** Definitions **** */ #define TIMER_16A_OFFSET 0 #define TIMER_16B_OFFSET 16 /* **** Functions **** */ int MXC_TMR_RevB_Init(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg, uint8_t clk_src) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); if (cfg == NULL) { return E_NULL_PTR; } uint32_t timerOffset; if (cfg->bitMode == TMR_BIT_MODE_16B) { timerOffset = TIMER_16B_OFFSET; } else { timerOffset = TIMER_16A_OFFSET; } // Default 32 bit timer if (cfg->bitMode & (TMR_BIT_MODE_16A | TMR_BIT_MODE_16B)) { tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_CASCADE; } else { tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_CASCADE; } // Clear interrupt flag tmr->intfl |= (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B); // Set the prescale tmr->ctrl0 |= (cfg->pres << timerOffset); // Select clock Source tmr->ctrl1 |= ((clk_src << MXC_F_TMR_REVB_CTRL1_CLKSEL_A_POS) << timerOffset); //TIMER_16B only supports compare, oneshot and continuous modes. switch (cfg->mode) { case TMR_MODE_ONESHOT: MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg); break; case TMR_MODE_CONTINUOUS: MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg); break; case TMR_MODE_COUNTER: if (cfg->bitMode == TMR_BIT_MODE_16B) { return E_NOT_SUPPORTED; } MXC_TMR_RevB_ConfigGeneric(tmr, cfg); break; case TMR_MODE_CAPTURE: if (cfg->bitMode == TMR_BIT_MODE_16B) { return E_NOT_SUPPORTED; } MXC_TMR_RevB_ConfigGeneric(tmr, cfg); break; case TMR_MODE_COMPARE: MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg); break; case TMR_MODE_GATED: if (cfg->bitMode == TMR_BIT_MODE_16B) { return E_NOT_SUPPORTED; } MXC_TMR_RevB_ConfigGeneric(tmr, cfg); break; case TMR_MODE_CAPTURE_COMPARE: if (cfg->bitMode == TMR_BIT_MODE_16B) { return E_NOT_SUPPORTED; } MXC_TMR_RevB_ConfigGeneric(tmr, cfg); break; case TMR_MODE_PWM: if (cfg->bitMode == TMR_BIT_MODE_16B) { return E_NOT_SUPPORTED; } MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg); break; } return E_NO_ERROR; } void MXC_TMR_RevB_ConfigGeneric(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg) { uint32_t timerOffset; int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); if (cfg == NULL) { return; } if (cfg->bitMode == TMR_BIT_MODE_16B) { timerOffset = TIMER_16B_OFFSET; } else { timerOffset = TIMER_16A_OFFSET; } tmr->ctrl0 |= (MXC_F_TMR_REVB_CTRL0_CLKEN_A << timerOffset); while (!(tmr->ctrl1 & (MXC_F_TMR_REVB_CTRL1_CLKRDY_A << timerOffset))) {} tmr->ctrl0 |= (cfg->mode << timerOffset); tmr->ctrl0 |= ((cfg->pol << MXC_F_TMR_REVB_CTRL0_POL_A_POS) << timerOffset); //enable timer interrupt if needed tmr->cnt = (0x1 << timerOffset); while (!(tmr->intfl & (MXC_F_TMR_REVB_INTFL_WRDONE_A << timerOffset))) {} tmr->cmp = (cfg->cmp_cnt << timerOffset); #if TARGET_NUM == 32655 || TARGET_NUM == 78000 || TARGET_NUM == 32690 || TARGET_NUM == 78002 tmr->ctrl1 &= ~(MXC_F_TMR_REVB_CTRL1_OUTEN_A << timerOffset); #else // on default disable timer gpio out //tmr->ctrl1 |= (MXC_F_TMR_REVB_CTRL1_OUTEN_A << timerOffset); #endif // If configured as TIMER_16B then enable the interrupt and start the timer if (cfg->bitMode == TMR_BIT_MODE_16B) { tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_IE_B; tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_B; while (!(tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKEN_B)) {} } } void MXC_TMR_RevB_Shutdown(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); // Disable timer and clear settings tmr->ctrl0 = 0; while (tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKRDY_A) {} } void MXC_TMR_RevB_Start(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_A; while (!(tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKEN_A)) {} } void MXC_TMR_RevB_Stop(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->ctrl0 &= ~MXC_F_TMR_REVB_CTRL0_EN_A; } int MXC_TMR_RevB_SetPWM(mxc_tmr_revb_regs_t *tmr, uint32_t pwm) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); if (pwm > (tmr->cmp)) { return E_BAD_PARAM; } while (tmr->cnt >= pwm) {} tmr->pwm = pwm; while (!(tmr->intfl & MXC_F_TMR_REVB_INTFL_WRDONE_A)) {} return E_NO_ERROR; } uint32_t MXC_TMR_RevB_GetCompare(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); return tmr->cmp; } uint32_t MXC_TMR_RevB_GetCapture(mxc_tmr_revb_regs_t *tmr) { uint32_t pwm; int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); // read pwm register twice pwm = tmr->pwm; pwm = tmr->pwm; return pwm; } uint32_t MXC_TMR_RevB_GetCount(mxc_tmr_revb_regs_t *tmr) { uint32_t cnt; int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); // read cnt register twice cnt = tmr->cnt; cnt = tmr->cnt; return cnt; } uint32_t MXC_TMR_RevB_GetPeriod(mxc_tmr_revb_regs_t *tmr, uint32_t clk_frequency, uint32_t prescalar, uint32_t frequency) { uint32_t periodTicks; int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); periodTicks = clk_frequency / (frequency * prescalar); return periodTicks; } void MXC_TMR_RevB_ClearFlags(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->intfl |= (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B); } uint32_t MXC_TMR_RevB_GetFlags(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); return (tmr->intfl & (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B)); } void MXC_TMR_RevB_EnableInt(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_IE_A | MXC_F_TMR_REVB_CTRL1_IE_B; } void MXC_TMR_RevB_DisableInt(mxc_tmr_revb_regs_t *tmr) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->ctrl1 &= ~(MXC_F_TMR_REVB_CTRL1_IE_A | MXC_F_TMR_REVB_CTRL1_IE_B); } void MXC_TMR_RevB_EnableWakeup(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); // Enable Timer wake-up source if (cfg->bitMode == TMR_BIT_MODE_16B) { tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_WE_B; } else { tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_WE_A; } } void MXC_TMR_RevB_DisableWakeup(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); // Disable Timer wake-up source if (cfg->bitMode == TMR_BIT_MODE_16B) { tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_WE_B; } else { tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_WE_A; } } void MXC_TMR_RevB_SetCompare(mxc_tmr_revb_regs_t *tmr, uint32_t cmp_cnt) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->cmp = cmp_cnt; } void MXC_TMR_RevB_SetCount(mxc_tmr_revb_regs_t *tmr, uint32_t cnt) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); tmr->cnt = cnt; while (!(tmr->intfl & MXC_F_TMR_REVB_INTFL_WRDONE_A)) {} } void MXC_TMR_RevB_TO_Start(mxc_tmr_revb_regs_t *tmr, uint32_t us) { uint64_t ticks; int clk_shift = 0; int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); if (us == 0) { return; } ticks = (uint64_t)us * (uint64_t)PeripheralClock / (uint64_t)1000000; while (ticks > 0xFFFFFFFFUL) { ticks >>= 1; ++clk_shift; } mxc_tmr_pres_t prescale = (mxc_tmr_pres_t)clk_shift << MXC_F_TMR_REVB_CTRL0_CLKDIV_A_POS; mxc_tmr_cfg_t cfg; // Initialize the timer in one-shot mode cfg.pres = prescale; cfg.mode = TMR_MODE_ONESHOT; cfg.bitMode = TMR_BIT_MODE_32; cfg.clock = MXC_TMR_APB_CLK; cfg.cmp_cnt = ticks; cfg.pol = 0; MXC_TMR_Stop((mxc_tmr_regs_t *)tmr); #if TARGET_NUM == 32662 MXC_TMR_Init((mxc_tmr_regs_t *)tmr, &cfg, false, MAP_A); #else MXC_TMR_Init((mxc_tmr_regs_t *)tmr, &cfg, false); #endif tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_CASCADE; MXC_TMR_ClearFlags((mxc_tmr_regs_t *)tmr); MXC_TMR_Start((mxc_tmr_regs_t *)tmr); } int MXC_TMR_RevB_GetTime(mxc_tmr_revb_regs_t *tmr, uint32_t ticks, uint32_t *time, mxc_tmr_unit_t *units) { int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr); (void)tmr_id; MXC_ASSERT(tmr_id >= 0); uint64_t temp_time = 0; uint32_t timerClock = PeripheralClock; uint32_t prescale = (tmr->ctrl0 & MXC_F_TMR_REVB_CTRL0_CLKDIV_A) >> MXC_F_TMR_REVB_CTRL0_CLKDIV_A_POS; temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000000); if (!(temp_time & 0xffffffff00000000)) { *time = temp_time; *units = TMR_UNIT_NANOSEC; return E_NO_ERROR; } temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000); if (!(temp_time & 0xffffffff00000000)) { *time = temp_time; *units = TMR_UNIT_MICROSEC; return E_NO_ERROR; } temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / timerClock; if (!(temp_time & 0xffffffff00000000)) { *time = temp_time; *units = TMR_UNIT_MILLISEC; return E_NO_ERROR; } temp_time = (uint64_t)ticks * (1 << (prescale & 0xF)) / timerClock; if (!(temp_time & 0xffffffff00000000)) { *time = temp_time; *units = TMR_UNIT_SEC; return E_NO_ERROR; } return E_INVALID; } int MXC_TMR_RevB_GetTicks(mxc_tmr_revb_regs_t *tmr, uint32_t time, mxc_tmr_unit_t units, uint32_t *ticks) { uint32_t unit_div0, unit_div1; uint32_t timerClock; uint32_t prescale; uint64_t temp_ticks; timerClock = PeripheralClock; prescale = ((tmr->ctrl0 & MXC_F_TMR_CTRL0_CLKDIV_A) >> MXC_F_TMR_CTRL0_CLKDIV_A_POS); switch (units) { case TMR_UNIT_NANOSEC: unit_div0 = 1000000; unit_div1 = 1000; break; case TMR_UNIT_MICROSEC: unit_div0 = 1000; unit_div1 = 1000; break; case TMR_UNIT_MILLISEC: unit_div0 = 1; unit_div1 = 1000; break; case TMR_UNIT_SEC: unit_div0 = 1; unit_div1 = 1; break; default: return E_BAD_PARAM; } temp_ticks = (uint64_t)time * (timerClock / unit_div0) / (unit_div1 * (1 << (prescale & 0xF))); //make sure ticks is within a 32 bit value if (!(temp_ticks & 0xffffffff00000000) && (temp_ticks & 0xffffffff)) { *ticks = temp_ticks; return E_NO_ERROR; } return E_INVALID; }