//****************************************************************************** void analogin_init(analogin_t *obj, PinName pin) { // Make sure pin is an analog pin we can use for ADC MBED_ASSERT((ADCName)pinmap_peripheral(pin, PinMap_ADC) != (ADCName)NC); // Set the object pointer obj->adc = MXC_ADC; obj->adccfg = MXC_ADCCFG; obj->adc_fifo = MXC_ADC_FIFO; obj->adc_pin = pin; // Set the ADC clock to the system clock frequency MXC_SET_FIELD(&MXC_CLKMAN->clk_ctrl, MXC_F_CLKMAN_CLK_CTRL_ADC_SOURCE_SELECT, (MXC_F_CLKMAN_CLK_CTRL_ADC_GATE_N | (MXC_E_CLKMAN_ADC_SOURCE_SELECT_SYSTEM << MXC_F_CLKMAN_CLK_CTRL_ADC_SOURCE_SELECT_POS))); // Enable AFE power MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_AFE_POWERED; // Setup and hold window MXC_SET_FIELD(&obj->adc->tg_ctrl0, MXC_F_ADC_TG_CTRL0_PGA_TRK_CNT, PGA_TRK_CNT); // Setup sampling count and timing MXC_SET_FIELD(&obj->adc->tg_ctrl1, (MXC_F_ADC_TG_CTRL1_PGA_ACQ_CNT | MXC_F_ADC_TG_CTRL1_ADC_ACQ_CNT | MXC_F_ADC_TG_CTRL1_ADC_SLP_CNT), ((ADC_PGA_CNT << MXC_F_ADC_TG_CTRL1_PGA_ACQ_CNT_POS) | (ADC_ACQ_CNT << MXC_F_ADC_TG_CTRL1_ADC_ACQ_CNT_POS) | (ADC_SLP_CNT << MXC_F_ADC_TG_CTRL1_ADC_SLP_CNT_POS) | (MXC_F_ADC_TG_CTRL1_ADC_BRST_CNT))); }
//****************************************************************************** void spi_frequency(spi_t *obj, int hz) { // Maximum frequency is half the system frequency MBED_ASSERT((unsigned int)hz <= (SystemCoreClock / 2)); unsigned clocks = ((SystemCoreClock / 2) / hz); // Figure out the divider ratio int clk_div = 1; while(clk_div < 10) { if(clocks < 0x10) { break; } clk_div++; clocks = clocks >> 1; } // Turn on the SPI clock if(obj->index == 0) { MXC_CLKMAN->sys_clk_ctrl_11_spi0 = clk_div; } else if(obj->index == 1) { MXC_CLKMAN->sys_clk_ctrl_12_spi1 = clk_div; } else if(obj->index == 2) { MXC_CLKMAN->sys_clk_ctrl_13_spi2 = clk_div; } else { MBED_ASSERT(0); } // Set the number of clocks to hold sclk high and low MXC_SET_FIELD(&obj->spi->mstr_cfg, (MXC_F_SPIM_MSTR_CFG_SCK_HI_CLK | MXC_F_SPIM_MSTR_CFG_SCK_LO_CLK), ((clocks << MXC_F_SPIM_MSTR_CFG_SCK_HI_CLK_POS) | (clocks << MXC_F_SPIM_MSTR_CFG_SCK_LO_CLK_POS))); }
//****************************************************************************** void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { MBED_ASSERT(obj->index < MXC_CFG_UART_INSTANCES); // objs[obj->index] = obj; switch (obj->index) { case 0: NVIC_SetVector(UART0_IRQn, (uint32_t)uart0_handler); NVIC_EnableIRQ(UART0_IRQn); break; case 1: NVIC_SetVector(UART1_IRQn, (uint32_t)uart1_handler); NVIC_EnableIRQ(UART1_IRQn); break; case 2: NVIC_SetVector(UART2_IRQn, (uint32_t)uart2_handler); NVIC_EnableIRQ(UART2_IRQn); break; case 3: NVIC_SetVector(UART3_IRQn, (uint32_t)uart3_handler); NVIC_EnableIRQ(UART3_IRQn); break; default: MBED_ASSERT(0); } if (irq == RxIrq) { // Enable RX FIFO Threshold Interrupt if (enable) { // Clear pending interrupts obj->uart->intfl = obj->uart->intfl; obj->uart->inten |= (MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS); } else { // Clear pending interrupts obj->uart->intfl = obj->uart->intfl; obj->uart->inten &= ~(MXC_F_UART_INTFL_RX_FIFO_NOT_EMPTY | UART_ERRORS); } } else if (irq == TxIrq) { // Set TX Almost Empty level to interrupt when empty MXC_SET_FIELD(&obj->uart->tx_fifo_ctrl, MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL, (MXC_UART_FIFO_DEPTH - 1) << MXC_F_UART_TX_FIFO_CTRL_FIFO_AE_LVL_POS); // Enable TX Almost Empty Interrupt if (enable) { // Clear pending interrupts obj->uart->intfl = obj->uart->intfl; obj->uart->inten |= MXC_F_UART_INTFL_TX_FIFO_AE; } else { // Clear pending interrupts obj->uart->intfl = obj->uart->intfl; obj->uart->inten &= ~MXC_F_UART_INTFL_TX_FIFO_AE; } } else { MBED_ASSERT(0); } }
//****************************************************************************** static void pwmout_update(pwmout_t* obj) { // Calculate and set the divider ratio int div = (obj->period * (SystemCoreClock/1000000))/32; if (div < 2){ div = 2; } MXC_SET_FIELD(&obj->pwm->rate_length, MXC_F_PT_RATE_LENGTH_RATE_CONTROL, div); // Change the duty cycle to adjust the pulse width obj->pwm->train = (0xFFFFFFFF << (32-((32*obj->pulse_width)/obj->period))); }
//****************************************************************************** void pwmout_init(pwmout_t* obj, PinName pin) { // Make sure the pin is free for GPIO use unsigned int port = (unsigned int)pin >> PORT_SHIFT; unsigned int port_pin = (unsigned int)pin & ~(0xFFFFFFFF << PORT_SHIFT); MBED_ASSERT(MXC_GPIO->free[port] & (0x1 << port_pin)); int i = 0; PinMap pwm = PinMap_PWM[0]; // Check if there is a pulse train already active on this port int pin_func = (MXC_GPIO->func_sel[port] & (0xF << (port_pin*4))) >> (port_pin*4); if((pin_func > 0) && (pin_func < 4)) { // Search through PinMap_PWM to find the active PT while(pwm.pin != (PinName)NC) { if((pwm.pin == pin) && (pwm.function == pin_func)) { break; } pwm = PinMap_PWM[++i]; } } else { // Search through PinMap_PWM to find an available PT int i = 0; while(pwm.pin != (PinName)NC && (i > -1)) { pwm = PinMap_PWM[i++]; if(pwm.pin == pin) { // Check each instance of PT while(1) { // Check to see if this PT instance is already in use if((((mxc_pt_regs_t*)pwm.peripheral)->rate_length & MXC_F_PT_RATE_LENGTH_MODE)) { i = -1; break; } // If all instances are in use, overwrite the last pwm = PinMap_PWM[++i]; if(pwm.pin != pin) { pwm = PinMap_PWM[--i]; i = -1; break; } } } } } // Make sure we found an available PWM generator MBED_ASSERT(pwm.pin != (PinName)NC); // Disable all pwm output MXC_PTG->ctrl = 0; // Enable the clock MXC_CLKMAN->clk_ctrl_2_pt = MXC_E_CLKMAN_CLK_SCALE_ENABLED; // Set the drive mode to normal MXC_SET_FIELD(&MXC_GPIO->out_mode[port], (0x7 << (port_pin*4)), (MXC_V_GPIO_OUT_MODE_NORMAL_DRIVE << (port_pin*4))); // Set the obj pointer to the propper PWM instance obj->pwm = (mxc_pt_regs_t*)pwm.peripheral; // Initialize object period and pulse width obj->period = -1; obj->pulse_width = -1; // Disable the output obj->pwm->train = 0x0; obj->pwm->rate_length = 0x0; // Configure the pin pin_mode(pin, (PinMode)PullNone); pin_function(pin, pwm.function); // default to 20ms: standard for servos, and fine for e.g. brightness control pwmout_period_us(obj, 20000); pwmout_write (obj, 0); // Enable the global pwm MXC_PTG->ctrl = MXC_F_PT_CTRL_ENABLE_ALL; }
//****************************************************************************** void analogout_init(dac_t *obj, PinName pin) { // Make sure pin is an analog pin we can use for ADC DACName dac = (DACName)pinmap_peripheral(pin, PinMap_DAC); MBED_ASSERT((DACName)dac != (DACName)NC); // Set the object pointer obj->dac = ((mxc_dac_regs_t*)MXC_DAC_GET_DAC((pin & 0x3))); obj->dac_fifo = ((mxc_dac_fifo_t*)MXC_DAC_GET_FIFO((pin & 0x3))); obj->index = (pin & 0x3); // Set the ADC clock to the system clock frequency MXC_SET_FIELD(&MXC_CLKMAN->clk_ctrl, MXC_F_CLKMAN_CLK_CTRL_ADC_SOURCE_SELECT, (MXC_F_CLKMAN_CLK_CTRL_ADC_GATE_N | (MXC_E_CLKMAN_ADC_SOURCE_SELECT_SYSTEM << MXC_F_CLKMAN_CLK_CTRL_ADC_SOURCE_SELECT_POS))); // Setup the OPAMP in follower mode switch(obj->index) { case 0: // Enable DAC clock MXC_CLKMAN->clk_ctrl_14_dac0 = MXC_E_CLKMAN_CLK_SCALE_ENABLED; // Enable OPAMP MXC_AFE->ctrl5 &= ~MXC_F_AFE_CTRL5_OP_CMP0; // Set the positive and negative inputs MXC_SET_FIELD(&MXC_AFE->ctrl4, (MXC_F_AFE_CTRL4_DAC_SEL_A | MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP0 | MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP0), ((0x1 << MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP0_POS) | (0x1 << MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP0_POS) | (0x0 << MXC_F_AFE_CTRL4_DAC_SEL_A_POS))); // Enable N and P channel inputs MXC_AFE->ctrl3 |= (MXC_F_AFE_CTRL3_EN_PCH_OPAMP0 | MXC_F_AFE_CTRL3_EN_NCH_OPAMP0); break; case 1: // Enable DAC clock MXC_CLKMAN->clk_ctrl_15_dac1 = MXC_E_CLKMAN_CLK_SCALE_ENABLED; // Enable OPAMP MXC_AFE->ctrl5 &= ~MXC_F_AFE_CTRL5_OP_CMP1; // Set the positive and negative inputs MXC_SET_FIELD(&MXC_AFE->ctrl4, (MXC_F_AFE_CTRL4_DAC_SEL_B | MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP1 | MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP1), ((0x1 << MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP1_POS) | (0x1 << MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP1_POS) | (0x1 << MXC_F_AFE_CTRL4_DAC_SEL_B_POS))); // Enable N and P channel inputs MXC_AFE->ctrl3 |= (MXC_F_AFE_CTRL3_EN_PCH_OPAMP1 | MXC_F_AFE_CTRL3_EN_NCH_OPAMP1); break; case 2: // Enable DAC clock MXC_CLKMAN->clk_ctrl_16_dac2 = MXC_E_CLKMAN_CLK_SCALE_ENABLED; // Enable OPAMP MXC_AFE->ctrl5 &= ~MXC_F_AFE_CTRL5_OP_CMP2; // Set the positive and negative inputs MXC_SET_FIELD(&MXC_AFE->ctrl4, (MXC_F_AFE_CTRL4_DAC_SEL_C | MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP2 | MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP2), ((0x1 << MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP2_POS) | (0x1 << MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP2_POS) | (0x2 << MXC_F_AFE_CTRL4_DAC_SEL_C_POS))); // Enable N and P channel inputs MXC_AFE->ctrl3 |= (MXC_F_AFE_CTRL3_EN_PCH_OPAMP2 | MXC_F_AFE_CTRL3_EN_NCH_OPAMP2); break; case 3: // Enable DAC clock MXC_CLKMAN->clk_ctrl_17_dac3 = MXC_E_CLKMAN_CLK_SCALE_ENABLED; // Enable OPAMP MXC_AFE->ctrl5 &= ~MXC_F_AFE_CTRL5_OP_CMP3; // Set the positive and negative inputs MXC_SET_FIELD(&MXC_AFE->ctrl4, (MXC_F_AFE_CTRL4_DAC_SEL_D | MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP3 | MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP3), ((0x1 << MXC_F_AFE_CTRL4_P_IN_SEL_OPAMP3_POS) | (0x1 << MXC_F_AFE_CTRL4_N_IN_SEL_OPAMP3_POS) | (0x3 << MXC_F_AFE_CTRL4_DAC_SEL_D_POS))); // Enable N and P channel inputs MXC_AFE->ctrl3 |= (MXC_F_AFE_CTRL3_EN_PCH_OPAMP3 | MXC_F_AFE_CTRL3_EN_NCH_OPAMP3); break; } // Enable AFE power MXC_PWRMAN->pwr_rst_ctrl |= MXC_F_PWRMAN_PWR_RST_CTRL_AFE_POWERED; // Setup internal voltage references MXC_SET_FIELD(&MXC_AFE->ctrl1, (MXC_F_AFE_CTRL1_REF_DAC_VOLT_SEL | MXC_F_AFE_CTRL1_REF_ADC_VOLT_SEL), (MXC_F_AFE_CTRL1_REF_ADC_POWERUP | MXC_F_AFE_CTRL1_REF_BLK_POWERUP | (MXC_E_AFE_REF_VOLT_SEL_1500 << MXC_F_AFE_CTRL1_REF_ADC_VOLT_SEL_POS))); // Disable interpolation obj->dac->ctrl0 &= MXC_F_DAC_CTRL0_INTERP_MODE; }