void spi_frequency(spi_t *obj, int hz) { uint32_t error = 0; uint32_t p_error = 0xffffffff; uint32_t ref = 0; uint8_t spr = 0; uint8_t ref_spr = 0; uint8_t ref_prescaler = 0; // bus clk uint32_t PCLK = bus_frequency(); uint8_t prescaler = 1; uint8_t divisor = 2; for (prescaler = 1; prescaler <= 8; prescaler++) { divisor = 2; for (spr = 0; spr <= 8; spr++, divisor *= 2) { ref = PCLK / (prescaler*divisor); if (ref > (uint32_t)hz) continue; error = hz - ref; if (error < p_error) { ref_spr = spr; ref_prescaler = prescaler - 1; p_error = error; } } } // set SPPR and SPR obj->spi->BR = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf); }
void spi_frequency(spi_t *obj, int hz) { uint32_t f_error = 0; uint32_t p_error = 0xffffffff; uint32_t ref = 0; uint32_t br = 0; uint32_t ref_spr = 0; uint32_t ref_prescaler = 0; uint32_t ref_dr = 0; // bus clk uint32_t PCLK = bus_frequency(); for (uint32_t i = 0; i < 4; i++) { for (br = 0; br <= 15; br++) { for (uint32_t dr = 0; dr < 2; dr++) { ref = (PCLK * (1U + dr) / baudrate_prescaler[i]) / baudrate_scaler[br]; if (ref > (uint32_t)hz) continue; f_error = hz - ref; if (f_error < p_error) { ref_spr = br; ref_prescaler = i; ref_dr = dr; p_error = f_error; } } } } // set PBR and BR obj->spi->CTAR[0] &= ~(SPI_CTAR_PBR_MASK | SPI_CTAR_BR_MASK | SPI_CTAR_DBR_MASK); obj->spi->CTAR[0] |= (ref_prescaler << SPI_CTAR_PBR_SHIFT) | (ref_spr << SPI_CTAR_BR_SHIFT) | (ref_dr << SPI_CTAR_DBR_SHIFT); }
/****************************************************************************** * Timer for us timing. ******************************************************************************/ static void pit_init(void) { SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT PIT->MCR = 0; // Enable PIT pit_ldval = bus_frequency() / 1000000; PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK; PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1 NVIC_SetVector(PIT0_IRQn, (uint32_t)pit0_isr); NVIC_EnableIRQ(PIT0_IRQn); }
/****************************************************************************** * Timer for us timing. ******************************************************************************/ static void pit_init(void) { SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT PIT->MCR = 0; // Enable PIT // Channel 1 PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF; PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK; // Chain to timer 0, disable Interrupts PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1 // Use channel 0 as a prescaler for channel 1 PIT->CHANNEL[0].LDVAL = (bus_frequency() + 500000) / 1000000 - 1; PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; // Start timer 0, disable interrupts }
void us_ticker_init(void) { if (us_ticker_inited) return; us_ticker_inited = 1; SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT PIT->MCR = 0; // Enable PIT clk_mhz = bus_frequency() / 1000000; timer_init(); ticker_init(); }