inline void I2C_setup() { // Enable I2C internal clock SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0 // External pull-up resistor PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); // SCL Frequency Divider // 400kHz -> 120 (0x85) @ 48 MHz F_BUS I2C0_F = 0x85; I2C0_FLT = 4; I2C0_C1 = I2C_C1_IICEN; I2C0_C2 = I2C_C2_HDRS; // High drive select // Enable I2C Interrupt NVIC_ENABLE_IRQ( IRQ_I2C0 ); }
bool PulsePositionInput::begin(uint8_t pin) { uint32_t channel; volatile void *reg; if (FTM0_MOD != 0xFFFF || (FTM0_SC & 0x7F) != FTM0_SC_VALUE) { FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; FTM0_SC = FTM0_SC_VALUE; #if defined(KINETISK) FTM0_MODE = 0; #endif } switch (pin) { case 6: channel = 4; reg = &FTM0_C4SC; break; case 9: channel = 2; reg = &FTM0_C2SC; break; case 10: channel = 3; reg = &FTM0_C3SC; break; case 20: channel = 5; reg = &FTM0_C5SC; break; case 22: channel = 0; reg = &FTM0_C0SC; break; case 23: channel = 1; reg = &FTM0_C1SC; break; #if defined(KINETISK) case 21: channel = 6; reg = &FTM0_C6SC; break; case 5: channel = 7; reg = &FTM0_C7SC; break; #endif default: return false; } prev = 0; write_index = 255; available_flag = false; ftm = (struct ftm_channel_struct *)reg; list[channel] = this; channelmask |= (1<<channel); *portConfigRegister(pin) = PORT_PCR_MUX(4); CSC_CHANGE(ftm, cscEdge); // input capture & interrupt on rising edge NVIC_SET_PRIORITY(IRQ_FTM0, 32); NVIC_ENABLE_IRQ(IRQ_FTM0); return true; }
void AudioInputI2S::begin(void) { //block_left_1st = NULL; //block_right_1st = NULL; //pinMode(3, OUTPUT); //digitalWriteFast(3, HIGH); //delayMicroseconds(500); //digitalWriteFast(3, LOW); // TODO: should we set & clear the I2S_RCSR_SR bit here? AudioOutputI2S::config_i2s(); CORE_PIN13_CONFIG = PORT_PCR_MUX(4); // pin 13, PTC5, I2S0_RXD0 DMA_CR = 0; DMA_TCD1_SADDR = &I2S0_RDR0; DMA_TCD1_SOFF = 0; DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); DMA_TCD1_NBYTES_MLNO = 2; DMA_TCD1_SLAST = 0; DMA_TCD1_DADDR = i2s_rx_buffer; DMA_TCD1_DOFF = 2; DMA_TCD1_CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; DMA_TCD1_DLASTSGA = -sizeof(i2s_rx_buffer); DMA_TCD1_BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; DMA_TCD1_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; DMAMUX0_CHCFG1 = DMAMUX_DISABLE; DMAMUX0_CHCFG1 = DMAMUX_SOURCE_I2S0_RX | DMAMUX_ENABLE; update_responsibility = update_setup(); DMA_SERQ = 1; // TODO: is I2S_RCSR_BCE appropriate if sync'd to transmitter clock? //I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_FRDE | I2S_RCSR_FR; NVIC_ENABLE_IRQ(IRQ_DMA_CH1); }
void init_servo(void) { // for servo SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic read-mod-write pinMode(12, OUTPUT); PDB0_MOD = 0xFFFF; PDB0_CNT = 0; PDB0_IDLY = 0; PDB0_SC = PDB_CONFIG; NVIC_ENABLE_IRQ(IRQ_PDB); // TODO: maybe this should be a higher priority than most // other interrupts (init all to some default?) PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; //servo_active_mask = 9; servo_active_mask = 8; //servo_pin[0] = 12; //servo_ticks[0] = usToTicks(600); servo_pin[3] = 11; servo_ticks[3] = usToTicks(2100); //pinMode(12, OUTPUT); pinMode(11, OUTPUT); }
uint8_t Servo::attach(int pin, int minimum, int maximum) { if (servoIndex < MAX_SERVOS) { pinMode(pin, OUTPUT); servo_pin[servoIndex] = pin; servo_ticks[servoIndex] = usToTicks(DEFAULT_PULSE_WIDTH); servo_active_mask |= (1<<servoIndex); min_ticks = usToTicks(minimum); max_ticks = usToTicks(maximum); if (!(SIM_SCGC6 & SIM_SCGC6_PDB)) { SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic bitset PDB0_MOD = 0xFFFF; PDB0_CNT = 0; PDB0_IDLY = 0; PDB0_SC = PDB_CONFIG; // TODO: maybe this should be a higher priority than most // other interrupts (init all to some default?) PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; } NVIC_ENABLE_IRQ(IRQ_PDB); } return servoIndex; }
bool PulsePositionInput::begin(uint8_t pin) { uint32_t channel; volatile void *reg; if (FTM0_MOD != 0xFFFF || FTM0_SC != (FTM_SC_CLKS(1) | FTM_SC_PS(0))) { FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); FTM0_MODE = 0; } switch (pin) { case 5: channel = 7; reg = &FTM0_C7SC; break; case 6: channel = 4; reg = &FTM0_C4SC; break; case 9: channel = 2; reg = &FTM0_C2SC; break; case 10: channel = 3; reg = &FTM0_C3SC; break; case 20: channel = 5; reg = &FTM0_C5SC; break; case 21: channel = 6; reg = &FTM0_C6SC; break; case 22: channel = 0; reg = &FTM0_C0SC; break; case 23: channel = 1; reg = &FTM0_C1SC; break; default: return false; } prev = 0; write_index = 255; available_flag = false; ftm = (struct ftm_channel_struct *)reg; ftm->csc = cscEdge; // input capture & interrupt on rising edge list[channel] = this; channelmask |= (1<<channel); *portConfigRegister(pin) = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; NVIC_SET_PRIORITY(IRQ_FTM0, 32); NVIC_ENABLE_IRQ(IRQ_FTM0); return true; }
void HAL_adc_init() { analog_init(); while (ADC0_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish while (ADC1_SC3 & ADC_SC3_CAL) {}; // Wait for calibration to finish NVIC_ENABLE_IRQ(IRQ_FTM1); }
void CIO::startInt() { // Initialise the DAC SIM_SCGC2 |= SIM_SCGC2_DAC0; DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 // Initialise ADC0 SIM_SCGC6 |= SIM_SCGC6_ADC0; ADC0_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | // Single-ended 12 bits, long sample time ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP; ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb ADC0_SC2 = ADC_SC2_REFSEL(0) | ADC_SC2_ADTRG; // Voltage ref external, hardware trigger ADC0_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples ADC0_SC3 |= ADC_SC3_CAL; while (ADC0_SC3 & ADC_SC3_CAL) // Wait for calibration ; uint16_t sum0 = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + // Plus side gain ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0; sum0 = (sum0 / 2U) | 0x8000U; ADC0_PG = sum0; ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; // Enable ADC interrupt, use A0 NVIC_ENABLE_IRQ(IRQ_ADC0); #if defined(SEND_RSSI_DATA) // Initialise ADC1 SIM_SCGC3 |= SIM_SCGC3_ADC1; ADC1_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | // Single-ended 12 bits, long sample time ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP; ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb ADC1_SC2 = ADC_SC2_REFSEL(0); // Voltage ref external, software trigger ADC1_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples ADC1_SC3 |= ADC_SC3_CAL; while (ADC1_SC3 & ADC_SC3_CAL) // Wait for calibration ; uint16_t sum1 = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + // Plus side gain ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; sum1 = (sum1 / 2U) | 0x8000U; ADC1_PG = sum1; #endif #if defined(EXTERNAL_OSC) // Set ADC0 to trigger from the LPTMR at 24 kHz SIM_SOPT7 = SIM_SOPT7_ADC0ALTTRGEN | // Enable ADC0 alternate trigger SIM_SOPT7_ADC0TRGSEL(14); // Trigger ADC0 by LPTMR0 CORE_PIN13_CONFIG = PORT_PCR_MUX(3); SIM_SCGC5 |= SIM_SCGC5_LPTIMER; // Enable Low Power Timer Access LPTMR0_CSR = 0; // Disable LPTMR0_PSR = LPTMR_PSR_PBYP; // Bypass prescaler/filter LPTMR0_CMR = (EXTERNAL_OSC / 24000) - 1; // Frequency divided by CMR + 1 LPTMR0_CSR = LPTMR_CSR_TPS(2) | // Pin: 0=CMP0, 1=xtal, 2=pin13 LPTMR_CSR_TMS; // Mode Select, 0=timer, 1=counter LPTMR0_CSR |= LPTMR_CSR_TEN; // Enable #else // Setup PDB for ADC0 at 24 kHz SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock PDB0_MOD = (F_BUS / 24000) - 1; // Timer period - 1 PDB0_IDLY = 0; // Interrupt delay PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0 PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_LDOK; // No prescaling PDB0_SC |= PDB_SC_SWTRIG; // Software trigger (reset and restart counter) #endif digitalWrite(PIN_PTT, m_pttInvert ? HIGH : LOW); digitalWrite(PIN_COSLED, LOW); digitalWrite(PIN_LED, HIGH); }
void FlexCAN::begin (uint32_t baud, const CAN_filter_t &mask, uint8_t txAlt, uint8_t rxAlt) { // set up the pins if (flexcanBase == FLEXCAN0_BASE) { dbg_println ("Begin setup of CAN0"); #if defined(__MK66FX1M0__) || defined(__MK64FX512__) // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) // 29=PTB18=CAN0_TX, 30=PTB19=CAN0_RX (alternative) if (txAlt == 1) CORE_PIN29_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); // | PORT_PCR_PE | PORT_PCR_PS; if (rxAlt == 1) CORE_PIN30_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2); #else // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) // 32=PTB18=CAN0_TX, 25=PTB19=CAN0_RX (alternative) if (txAlt == 1) CORE_PIN32_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); // | PORT_PCR_PE | PORT_PCR_PS; if (rxAlt == 1) CORE_PIN25_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2); #endif } #if defined(INCLUDE_FLEXCAN_CAN1) else if (flexcanBase == FLEXCAN1_BASE) { dbg_println("Begin setup of CAN1"); // 33=PTE24=CAN1_TX, 34=PTE25=CAN1_RX (default) // NOTE: Alternative CAN1 pins are not broken out on Teensy 3.6 CORE_PIN33_CONFIG = PORT_PCR_MUX(2); CORE_PIN34_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; } #endif // select clock source 16MHz xtal OSC0_CR |= OSC_ERCLKEN; if (flexcanBase == FLEXCAN0_BASE) { SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0; #if defined(INCLUDE_FLEXCAN_CAN1) } else if (flexcanBase == FLEXCAN1_BASE) { SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1; #endif } FLEXCANb_CTRL1(flexcanBase) &= ~FLEXCAN_CTRL_CLK_SRC; // enable CAN FLEXCANb_MCR (flexcanBase) |= FLEXCAN_MCR_FRZ; FLEXCANb_MCR (flexcanBase) &= ~FLEXCAN_MCR_MDIS; while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_LPM_ACK) ; // soft reset FLEXCANb_MCR (flexcanBase) ^= FLEXCAN_MCR_SOFT_RST; while (FLEXCANb_MCR (flexcanBase) & FLEXCAN_MCR_SOFT_RST) ; // wait for freeze ack while (!(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK)) ; // disable self-reception FLEXCANb_MCR (flexcanBase) |= FLEXCAN_MCR_SRX_DIS; /* now using a system that tries to automatically generate a viable baud setting. Bear these things in mind: - The master clock is 16Mhz - You can freely divide it by anything from 1 to 256 - There is always a start bit (+1) - The rest (prop, seg1, seg2) are specified 1 less than their actual value (aka +1) - This gives the low end bit timing as 5 (1 + 1 + 2 + 1) and the high end 25 (1 + 8 + 8 + 8) A worked example: 16Mhz clock, divisor = 19+1, bit values add up to 16 = 16Mhz / 20 / 16 = 50k baud */ // have to find a divisor that ends up as close to the target baud as possible while keeping the end result between 5 and 25 uint32_t divisor = 0; uint32_t bestDivisor = 0; uint32_t result = 16000000 / baud / (divisor + 1); int error = baud - (16000000 / (result * (divisor + 1))); int bestError = error; while (result > 5) { divisor++; result = 16000000 / baud / (divisor + 1); if (result <= 25) { error = baud - (16000000 / (result * (divisor + 1))); if (error < 0) error *= -1; // if this error is better than we've ever seen then use it - it's the best option if (error < bestError) { bestError = error; bestDivisor = divisor; } // If this is equal to a previously good option then // switch to it but only if the bit time result was in the middle of the range // this biases the output to use the middle of the range all things being equal // Otherwise it might try to use a higher divisor and smaller values for prop, seg1, seg2 // and that's not necessarily the best idea. if ((error == bestError) && (result > 11) && (result < 19)) { bestError = error; bestDivisor = divisor; } } } divisor = bestDivisor; result = 16000000 / baud / (divisor + 1); if ((result < 5) || (result > 25) || (bestError > 300)) { Serial.println ("Abort in CAN begin. Couldn't find a suitable baud config!"); return; } result -= 5; // the bitTimingTable is offset by 5 since there was no reason to store bit timings for invalid numbers uint8_t propSeg = bitTimingTable[result][0]; uint8_t pSeg1 = bitTimingTable[result][1]; uint8_t pSeg2 = bitTimingTable[result][2]; // baud rate debug information dbg_println ("Bit time values:"); dbg_print ("Prop = "); dbg_println (propSeg + 1); dbg_print ("Seg1 = "); dbg_println (pSeg1 + 1); dbg_print ("Seg2 = "); dbg_println (pSeg2 + 1); dbg_print ("Divisor = "); dbg_println (divisor + 1); FLEXCANb_CTRL1 (flexcanBase) = (FLEXCAN_CTRL_PROPSEG(propSeg) | FLEXCAN_CTRL_RJW(1) | FLEXCAN_CTRL_ERR_MSK | FLEXCAN_CTRL_PSEG1(pSeg1) | FLEXCAN_CTRL_PSEG2(pSeg2) | FLEXCAN_CTRL_PRESDIV(divisor)); // enable per-mailbox filtering FLEXCANb_MCR(flexcanBase) |= FLEXCAN_MCR_IRMQ; // now have to set mask and filter for all the Rx mailboxes or they won't receive anything by default. for (uint8_t c = 0; c < NUM_MAILBOXES - numTxMailboxes; c++) { setMask (0, c); setFilter (mask, c); } // start the CAN FLEXCANb_MCR(flexcanBase) &= ~(FLEXCAN_MCR_HALT); // wait till exit of freeze mode while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK) ; // wait till ready while (FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_NOT_RDY) ; setNumTxBoxes (2); #if defined(__MK20DX256__) NVIC_SET_PRIORITY (IRQ_CAN_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN_MESSAGE); #elif defined(__MK64FX512__) NVIC_SET_PRIORITY (IRQ_CAN0_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN0_MESSAGE); #elif defined(__MK66FX1M0__) if (flexcanBase == FLEXCAN0_BASE) { NVIC_SET_PRIORITY (IRQ_CAN0_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN0_MESSAGE); } else { NVIC_SET_PRIORITY (IRQ_CAN1_MESSAGE, IRQ_PRIORITY); NVIC_ENABLE_IRQ (IRQ_CAN1_MESSAGE); } #endif // enable interrupt masks for all 16 mailboxes FLEXCANb_IMASK1 (flexcanBase) = 0xFFFF; dbg_println ("CAN initialized properly"); }
bool PulsePositionOutput::begin(uint8_t txPin, uint8_t framePin) { uint32_t channel; volatile void *reg; if (FTM0_MOD != 0xFFFF || FTM0_SC != (FTM_SC_CLKS(1) | FTM_SC_PS(0))) { FTM0_SC = 0; FTM0_CNT = 0; FTM0_MOD = 0xFFFF; FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); FTM0_MODE = 0; } switch (txPin) { case 5: channel = 7; reg = &FTM0_C7SC; break; case 6: channel = 4; reg = &FTM0_C4SC; break; case 9: channel = 2; reg = &FTM0_C2SC; break; case 10: channel = 3; reg = &FTM0_C3SC; break; case 20: channel = 5; reg = &FTM0_C5SC; break; case 21: channel = 6; reg = &FTM0_C6SC; break; case 22: channel = 0; reg = &FTM0_C0SC; break; case 23: channel = 1; reg = &FTM0_C1SC; break; default: return false; } if (framePin < NUM_DIGITAL_PINS) { framePinReg = portOutputRegister(framePin); pinMode(framePin, OUTPUT); *framePinReg = 1; } else { framePinReg = NULL; } state = 0; current_channel = 0; total_channels = 0; ftm = (struct ftm_channel_struct *)reg; ftm->cv = 200; ftm->csc = cscSet; // set on compare match & interrupt list[channel] = this; channelmask |= (1<<channel); *portConfigRegister(txPin) = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; NVIC_SET_PRIORITY(IRQ_FTM0, 32); NVIC_ENABLE_IRQ(IRQ_FTM0); return true; }
// ------------------------------------------------------------------------------------------------------ // Initialize I2C - initializes I2C as Master or address range Slave // return: none // parameters: // mode = I2C_MASTER, I2C_SLAVE // address1 = 1st 7bit address for specifying Slave address range (ignored for Master mode) // address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode) // pins = Wire: I2C_PINS_18_19, I2C_PINS_16_17 / Wire1: I2C_PINS_29_30, I2C_PINS_26_31 // pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT // rate = I2C_RATE_100, I2C_RATE_200, I2C_RATE_300, I2C_RATE_400, I2C_RATE_600, I2C_RATE_800, I2C_RATE_1000, // I2C_RATE_1200, I2C_RATE_1500, I2C_RATE_2000, I2C_RATE_2400 // void i2c_t3::begin_(struct i2cStruct* i2c, uint8_t bus, i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins, i2c_pullup pullup, i2c_rate rate) { // Enable I2C internal clock if(bus == 0) SIM_SCGC4 |= SIM_SCGC4_I2C0; #if I2C_BUS_NUM >= 2 if(bus == 1) SIM_SCGC4 |= SIM_SCGC4_I2C1; #endif i2c->currentMode = mode; // Set mode i2c->currentStatus = I2C_WAITING; // reset status // Set Master/Slave address (zeroed in Master to prevent accidental Rx when setup is changed dynamically) if(i2c->currentMode == I2C_MASTER) { *(i2c->C2) = I2C_C2_HDRS; // Set high drive select *(i2c->A1) = 0; *(i2c->RA) = 0; } else { *(i2c->C2) = (address2) ? (I2C_C2_HDRS|I2C_C2_RMEN) // Set high drive select and range-match enable : I2C_C2_HDRS; // Set high drive select // set Slave address, if two addresses are given, setup range and put lower address in A1, higher in RA *(i2c->A1) = (address2) ? ((address1 < address2) ? (address1<<1) : (address2<<1)) : (address1<<1); *(i2c->RA) = (address2) ? ((address1 < address2) ? (address2<<1) : (address1<<1)) : 0; } // Setup pins and options (note: does not "unset" unused pins if dynamically changed, must be done elsewhere) // As noted in original TwoWire.cpp, internal pullup is strong (about 190 ohms), but it can work if other // devices on bus have strong enough pulldown devices. uint32_t pinConfig0 = (pullup == I2C_PULLUP_EXT) ? (PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE) : (PORT_PCR_MUX(2)|PORT_PCR_PE|PORT_PCR_PS); #if I2C_BUS_NUM >= 2 uint32_t pinConfig1 = (pullup == I2C_PULLUP_EXT) ? (PORT_PCR_MUX(6)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE) : (PORT_PCR_MUX(6)|PORT_PCR_PE|PORT_PCR_PS); #endif // The I2C interfaces are associated with the pins as follows: // I2C0 : I2C_PINS_18_19, I2C_PINS_16_17 // I2C1 : I2C_PINS_29_30, I2C_PINS_26_31 // // If pins are given an impossible value (eg. I2C0 with I2C_PINS_26_31) then the default pins will be // used, which for I2C0 is I2C_PINS_18_19, and for I2C1 is I2C_PINS_29_30 // if(bus == 0) { if(pins == I2C_PINS_16_17) { i2c->currentPins = I2C_PINS_16_17; CORE_PIN16_CONFIG = pinConfig0; CORE_PIN17_CONFIG = pinConfig0; } else { i2c->currentPins = I2C_PINS_18_19; CORE_PIN18_CONFIG = pinConfig0; CORE_PIN19_CONFIG = pinConfig0; } } #if I2C_BUS_NUM >= 2 if(bus == 1) { if(pins == I2C_PINS_26_31) { i2c->currentPins = I2C_PINS_26_31; CORE_PIN26_CONFIG = pinConfig1; CORE_PIN31_CONFIG = pinConfig1; } else { i2c->currentPins = I2C_PINS_29_30; CORE_PIN29_CONFIG = pinConfig0; CORE_PIN30_CONFIG = pinConfig0; } } #endif // Set rate and filter #if F_BUS == 48000000 switch(rate) // Freq SCL Div { // ---- ------- case I2C_RATE_50: *(i2c->F) = 0x2F; break; // 50k 960 case I2C_RATE_100: *(i2c->F) = 0x27; break; // 100k 480 case I2C_RATE_200: *(i2c->F) = 0x1F; break; // 200k 240 case I2C_RATE_300: *(i2c->F) = 0x1D; break; // 300k 160 case I2C_RATE_400: *(i2c->F) = 0x85; break; // 400k 120 case I2C_RATE_600: *(i2c->F) = 0x14; break; // 600k 80 case I2C_RATE_800: *(i2c->F) = 0x45; break; // 800k 60 case I2C_RATE_1000: *(i2c->F) = 0x0D; break; // 1.0M 48 case I2C_RATE_1200: *(i2c->F) = 0x0B; break; // 1.2M 40 case I2C_RATE_1500: *(i2c->F) = 0x09; break; // 1.5M 32 case I2C_RATE_2000: *(i2c->F) = 0x02; break; // 2.0M 24 case I2C_RATE_2400: *(i2c->F) = 0x00; break; // 2.4M 20 default: *(i2c->F) = 0x27; break; // 100k 480 (defaults to slowest) } *(i2c->FLT) = 4; #elif F_BUS == 24000000 switch(rate) // Freq SCL Div { // ---- ------- case I2C_RATE_50: *(i2c->F) = 0x27; break; // 50k 480 case I2C_RATE_100: *(i2c->F) = 0x1F; break; // 100k 240 case I2C_RATE_200: *(i2c->F) = 0x85; break; // 200k 120 case I2C_RATE_300: *(i2c->F) = 0x14; break; // 300k 80 case I2C_RATE_400: *(i2c->F) = 0x45; break; // 400k 60 case I2C_RATE_600: *(i2c->F) = 0x0B; break; // 600k 40 case I2C_RATE_800: *(i2c->F) = 0x05; break; // 800k 30 case I2C_RATE_1000: *(i2c->F) = 0x02; break; // 1.0M 24 case I2C_RATE_1200: *(i2c->F) = 0x00; break; // 1.2M 20 default: *(i2c->F) = 0x1F; break; // 100k 240 (defaults to slowest) } *(i2c->FLT) = 2; #else #error "F_BUS must be 48 MHz or 24 MHz" #endif // Set config registers if(i2c->currentMode == I2C_MASTER) *(i2c->C1) = I2C_C1_IICEN; // Master - enable I2C (hold in Rx mode, intr disabled) else *(i2c->C1) = I2C_C1_IICEN|I2C_C1_IICIE; // Slave - enable I2C and interrupts // Nested Vec Interrupt Ctrl - enable I2C interrupt if(bus == 0) { NVIC_ENABLE_IRQ(IRQ_I2C0); I2C0_INTR_FLAG_INIT; // init I2C0 interrupt flag if used } #if I2C_BUS_NUM >= 2 if(bus == 1) { NVIC_ENABLE_IRQ(IRQ_I2C1); I2C1_INTR_FLAG_INIT; // init I2C1 interrupt flag if used } #endif #ifdef I2C_DEBUG if(!Serial) Serial.begin(115200); i2cDebugTimer.begin(printI2CDebug, 500); // 500us period, 2kHz timer #endif }
/******************************************************************************* * Enable Driver *******************************************************************************/ void SnoozeCompare::enableDriver( void ) { if ( mode == RUN_LP ) { return; } if ( mode == VLPW || mode == VLPS ) { IRQ_NUMBER_t IRQ_CMP; switch (pin) { case 11: IRQ_CMP = IRQ_CMP0; break; #if defined(KINETISK) case 9: IRQ_CMP = IRQ_CMP1; break; case 4: IRQ_CMP = IRQ_CMP2; break; #endif default: IRQ_CMP = IRQ_CMP; return; } return_priority = NVIC_GET_PRIORITY( IRQ_CMP );//get current priority int priority = nvic_execution_priority( );// get current priority // if running from handler mode set priority higher than current handler priority = ( priority < 256 ) && ( ( priority - 16 ) > 0 ) ? priority - 16 : 128; NVIC_SET_PRIORITY( IRQ_CMP, priority );//set priority to new level __disable_irq( ); return_cmp_irq = _VectorsRam[IRQ_CMP+16];// save prev isr attachInterruptVector( IRQ_CMP, wakeupIsr ); __enable_irq( ); } if ( SIM_SCGC4 & SIM_SCGC4_CMP ) SIM_SCGC4_clock_active = true; else SIM_SCGC4 |= SIM_SCGC4_CMP; CR0 = *cmpx_cr0; CR1 = *cmpx_cr1; SCR = *cmpx_scr; FPR = *cmpx_fpr; MUXCR = *cmpx_muxcr; DACCR = *cmpx_daccr; uint8_t _pin = 0; *cmpx_cr0 = 0; *cmpx_cr1 = 0; *cmpx_scr = 0; #if defined(__MKL26Z64__) || defined(__MK66FX1M0__) if ( SIM_SCGC5 & SIM_SCGC5_LPTIMER ) SIM_SCGC5_clock_active = true; else SIM_SCGC5 |= SIM_SCGC5_LPTIMER; PSR = LPTMR0_PSR; CMR = LPTMR0_CMR; CSR = LPTMR0_CSR; #endif if ( pin == 11 ) { if ( mode >= LLS ) llwu_configure_modules_mask( LLWU_CMP0_MOD ); return_core_pin_config[0] = CORE_PIN11_CONFIG; CORE_PIN11_CONFIG = PORT_PCR_MUX( 0 ); _pin = 0x00; } else if ( pin == 4 ) { #if defined(KINETISK) if ( mode >= LLS ) llwu_configure_modules_mask( LLWU_CMP2_MOD ); return_core_pin_config[1] = CORE_PIN4_CONFIG; CORE_PIN4_CONFIG = PORT_PCR_MUX( 0 ); _pin = 0x01; #else return; #endif } else if ( pin == 9 ) { #if defined(KINETISK) if ( mode >= LLS ) llwu_configure_modules_mask( LLWU_CMP1_MOD ); return_core_pin_config[2] = CORE_PIN9_CONFIG; CORE_PIN9_CONFIG = PORT_PCR_MUX( 0 ); _pin = 0x01; #else return; #endif } // save if isr is already enabled and enable isr if not if ( mode == VLPW || mode == VLPS ) { IRQ_NUMBER_t IRQ_CMP; switch (pin) { case 11: IRQ_CMP = IRQ_CMP0; break; #if defined(KINETISK) case 9: IRQ_CMP = IRQ_CMP1; break; case 4: IRQ_CMP = IRQ_CMP2; break; #endif default: IRQ_CMP = IRQ_CMP; return; } return_isr_enabled = NVIC_IS_ENABLED( IRQ_CMP ); if ( return_isr_enabled == 0 ) NVIC_ENABLE_IRQ( IRQ_CMP ); } // setup compare *cmpx_cr0 = CMP_CR0_FILTER_CNT( 0x07 ); if ( type == CHANGE ) *cmpx_scr = CMP_SCR_CFF | CMP_SCR_CFR | CMP_SCR_IEF | CMP_SCR_IER; else if ( type == RISING || type == HIGH ) *cmpx_scr = CMP_SCR_CFF | CMP_SCR_CFR | CMP_SCR_IER; else if ( type == FALLING || type == LOW ) *cmpx_scr = CMP_SCR_CFF | CMP_SCR_CFR | CMP_SCR_IEF; else return; uint8_t tap = ( threshold_crossing/0.0515625 ) - 1; *cmpx_fpr = 0x00; *cmpx_muxcr = CMP_MUXCR_MSEL( 0x07 ) | CMP_MUXCR_PSEL( _pin ); *cmpx_daccr = CMP_DACCR_DACEN | CMP_DACCR_VRSEL | CMP_DACCR_VOSEL( tap ); #if defined(__MKL26Z64__) || defined(__MK66FX1M0__) // compare needs lptmr to operate in low power with LC, 3.6 *cmpx_cr1 = CMP_CR1_EN | CMP_CR1_TRIGM; SIM_SCGC5 |= SIM_SCGC5_LPTIMER; LPTMR0_CSR = 0; LPTMR0_PSR = LPTMR_PSR_PBYP | LPTMR_PSR_PCS( LPTMR_LPO );//LPO Clock LPTMR0_CMR = 1; LPTMR0_CSR = LPTMR_CSR_TEN | LPTMR_CSR_TCF; #else *cmpx_cr1 = CMP_CR1_EN; #endif }
void i2c_setup() { for ( uint8_t ch = ISSI_I2C_FirstBus_define; ch < ISSI_I2C_Buses_define + ISSI_I2C_FirstBus_define; ch++ ) { #if defined(_kinetis_) volatile uint8_t *I2C_F = (uint8_t*)(&I2C0_F) + i2c_offset[ch]; volatile uint8_t *I2C_FLT = (uint8_t*)(&I2C0_FLT) + i2c_offset[ch]; volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; volatile uint8_t *I2C_C2 = (uint8_t*)(&I2C0_C2) + i2c_offset[ch]; switch ( ch ) { case 0: // Enable I2C internal clock SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0 // External pull-up resistor PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); break; #if defined(_kii_v2_) case 1: // Enable I2C internal clock SIM_SCGC4 |= SIM_SCGC4_I2C1; // Bus 1 // External pull-up resistor PORTC_PCR10 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); PORTC_PCR11 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); break; #endif } // SCL Frequency Divider #if ISSI_Chip_31FL3731_define == 1 && defined(_kii_v1_) // 0x53 -> 48 MHz / (2 * 72) = 333.333 kBaud // 0x40 => mul(2) // 0x13 => ICR(30) *I2C_F = 0x53; *I2C_FLT = 0x05; #elif ISSI_Chip_31FL3731_define == 1 && defined(_kii_v2_) // 0x4E -> 36 MHz / (2 * 56) = 321.428 kBaud // 0x40 => mul(2) // 0x0E => ICR(56) *I2C_F = 0x4E; *I2C_FLT = 0x04; #elif ISSI_Chip_31FL3732_define == 1 || ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 /* // Works // 0x84 -> 36 MHz / (4 * 28) = 321.428 kBaud // 0x80 => mul(4) // 0x04 => ICR(28) *I2C_F = 0x84; *I2C_FLT = 0x02; // Also works, 80 fps, no errors (flicker?) // 0x0C -> 36 MHz / (1 * 44) = 818.181 kBaud // 0x00 => mul(1) // 0x0C => ICR(44) *I2C_F = 0x0C; *I2C_FLT = 0x02; // Glitch protection, reduce if you see bus errors */ // Also works, 86 fps, no errors, using frame delay of 50 us // 0x40 -> 36 MHz / (2 * 20) = 900 kBaud // 0x40 => mul(2) // 0x00 => ICR(20) *I2C_F = 0x40; *I2C_FLT = 0x02; #endif *I2C_C1 = I2C_C1_IICEN; *I2C_C2 = I2C_C2_HDRS; // High drive select switch ( ch ) { case 0: // Enable I2C Interrupt NVIC_ENABLE_IRQ( IRQ_I2C0 ); // Set priority below USB, but not too low to maintain performance NVIC_SET_PRIORITY( IRQ_PIT_CH0, I2C_Priority_define ); break; #if defined(_kii_v2_) case 1: // Enable I2C Interrupt NVIC_ENABLE_IRQ( IRQ_I2C1 ); // Set priority below USB, but not too low to maintain performance NVIC_SET_PRIORITY( IRQ_PIT_CH1, I2C_Priority_define ); break; #endif } #elif defined(_sam_) #if ISSI_Chip_31FL3731_define == 1 #define BAUD 400000 #define CK 1 #elif ISSI_Chip_31FL3732_define == 1 || ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 #define BAUD 800000 #define CK 0 #endif switch ( ch ) { case 0: // Enable Peripheral / Disable PIO PIOA->PIO_PDR = (1 << 3) | (1 << 4); // Enable i2c clock PMC->PMC_PCER0 = (1 << ID_TWI0); break; case 1: MATRIX->CCFG_SYSIO |= CCFG_SYSIO_SYSIO4 | CCFG_SYSIO_SYSIO5; // Switch PB4 from TDI to GPIO PIOB->PIO_PDR = (1 << 4) | (1 << 5); PMC->PMC_PCER0 = (1 << ID_TWI1); break; } Twi *twi_dev = twi_devs[ch]; uint16_t div = (F_CPU/BAUD - 4) / (2<<CK); // Set clock twi_dev->TWI_CWGR = TWI_CWGR_CLDIV(div) + TWI_CWGR_CHDIV(div) + TWI_CWGR_CKDIV(CK); // Enable master mode twi_dev->TWI_CR = TWI_CR_MSDIS | TWI_CR_SVDIS; twi_dev->TWI_CR = TWI_CR_MSEN; switch ( ch ) { case 0: NVIC_SetPriority(TWI0_IRQn, I2C_Priority_define); NVIC_EnableIRQ(TWI0_IRQn); break; case 1: NVIC_SetPriority(TWI1_IRQn, I2C_Priority_define); NVIC_EnableIRQ(TWI1_IRQn); break; } #endif } }
void AudioInputAnalog::begin(unsigned int pin) { uint32_t i, sum=0; // pin must be 0 to 13 (for A0 to A13) // or 14 to 23 for digital pin numbers A0-A9 // or 34 to 37 corresponding to A10-A13 if (pin > 23 && !(pin >= 34 && pin <= 37)) return; //pinMode(2, OUTPUT); //pinMode(3, OUTPUT); //digitalWriteFast(3, HIGH); //delayMicroseconds(500); //digitalWriteFast(3, LOW); // Configure the ADC and run at least one software-triggered // conversion. This completes the self calibration stuff and // leaves the ADC in a state that's mostly ready to use analogReadRes(16); analogReference(INTERNAL); // range 0 to 1.2 volts //analogReference(DEFAULT); // range 0 to 3.3 volts analogReadAveraging(8); // Actually, do many normal reads, to start with a nice DC level for (i=0; i < 1024; i++) { sum += analogRead(pin); } dc_average = sum >> 10; // testing only, enable adc interrupt //ADC0_SC1A |= ADC_SC1_AIEN; //while ((ADC0_SC1A & ADC_SC1_COCO) == 0) ; // wait //NVIC_ENABLE_IRQ(IRQ_ADC0); // set the programmable delay block to trigger the ADC at 44.1 kHz SIM_SCGC6 |= SIM_SCGC6_PDB; PDB0_MOD = PDB_PERIOD; PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; PDB0_CH0C1 = 0x0101; // enable the ADC for hardware trigger and DMA ADC0_SC2 |= ADC_SC2_ADTRG | ADC_SC2_DMAEN; // set up a DMA channel to store the ADC data SIM_SCGC7 |= SIM_SCGC7_DMA; SIM_SCGC6 |= SIM_SCGC6_DMAMUX; DMA_CR = 0; DMA_TCD2_SADDR = &ADC0_RA; DMA_TCD2_SOFF = 0; DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); DMA_TCD2_NBYTES_MLNO = 2; DMA_TCD2_SLAST = 0; DMA_TCD2_DADDR = analog_rx_buffer; DMA_TCD2_DOFF = 2; DMA_TCD2_CITER_ELINKNO = sizeof(analog_rx_buffer) / 2; DMA_TCD2_DLASTSGA = -sizeof(analog_rx_buffer); DMA_TCD2_BITER_ELINKNO = sizeof(analog_rx_buffer) / 2; DMA_TCD2_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; DMAMUX0_CHCFG2 = DMAMUX_DISABLE; DMAMUX0_CHCFG2 = DMAMUX_SOURCE_ADC0 | DMAMUX_ENABLE; update_responsibility = update_setup(); DMA_SERQ = 2; NVIC_ENABLE_IRQ(IRQ_DMA_CH2); }
// Setup connection to other side // - Only supports a single slave and master // - If USB has been initiallized at this point, this side is the master // - If both sides assert master, flash error leds void Connect_setup( uint8_t master ) { // Indication that UARTs are not ready uarts_configured = 0; // Register Connect CLI dictionary CLI_registerDictionary( uartConnectCLIDict, uartConnectCLIDictName ); // Check if master Connect_master = master; if ( Connect_master ) Connect_id = 0; // 0x00 is always the master Id // UART0 setup // UART1 setup // Setup the the UART interface for keyboard data input SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating SIM_SCGC4 |= SIM_SCGC4_UART1; // Disable clock gating // Pin Setup for UART0 / UART1 PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin PORTE_PCR0 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin PORTE_PCR1 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin // Baud Rate setting UART0_BDH = (uint8_t)(Connect_baud >> 8); UART0_BDL = (uint8_t)Connect_baud; UART0_C4 = Connect_baudFine; UART1_BDH = (uint8_t)(Connect_baud >> 8); UART1_BDL = (uint8_t)Connect_baud; UART1_C4 = Connect_baudFine; // 8 bit, Even Parity, Idle Character bit after stop // NOTE: For 8 bit with Parity you must enable 9 bit transmission (pg. 1065) // You only need to use UART0_D for 8 bit reading/writing though // UART_C1_M UART_C1_PE UART_C1_PT UART_C1_ILT UART0_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT; UART1_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT; // Only using Tx Fifos UART0_PFIFO = UART_PFIFO_TXFE; UART1_PFIFO = UART_PFIFO_TXFE; // Setup DMA clocks SIM_SCGC6 |= SIM_SCGC6_DMAMUX; SIM_SCGC7 |= SIM_SCGC7_DMA; // Start with channels disabled first DMAMUX0_CHCFG0 = 0; DMAMUX0_CHCFG1 = 0; // Configure DMA channels //DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK; // TODO What's this? DMA_TCD0_CSR = 0; DMA_TCD1_CSR = 0; // Default control register DMA_CR = 0; // DMA Priority DMA_DCHPRI0 = 0; // Ch 0, priority 0 DMA_DCHPRI1 = 1; // ch 1, priority 1 // Clear error interrupts DMA_EEI = 0; // Setup TCD DMA_TCD0_SADDR = (uint32_t*)&UART0_D; DMA_TCD1_SADDR = (uint32_t*)&UART1_D; DMA_TCD0_SOFF = 0; DMA_TCD1_SOFF = 0; // No modulo, 8-bit transfer size DMA_TCD0_ATTR = DMA_TCD_ATTR_SMOD(0) | DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DMOD(0) | DMA_TCD_ATTR_DSIZE(0); DMA_TCD1_ATTR = DMA_TCD_ATTR_SMOD(0) | DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DMOD(0) | DMA_TCD_ATTR_DSIZE(0); // One byte transferred at a time DMA_TCD0_NBYTES_MLNO = 1; DMA_TCD1_NBYTES_MLNO = 1; // Source address does not change DMA_TCD0_SLAST = 0; DMA_TCD1_SLAST = 0; // Destination buffer DMA_TCD0_DADDR = (uint32_t*)uart_rx_buf[0].buffer; DMA_TCD1_DADDR = (uint32_t*)uart_rx_buf[1].buffer; // Incoming byte, increment by 1 in the rx buffer DMA_TCD0_DOFF = 1; DMA_TCD1_DOFF = 1; // Single major loop, must be the same value DMA_TCD0_CITER_ELINKNO = UART_Buffer_Size; DMA_TCD1_CITER_ELINKNO = UART_Buffer_Size; DMA_TCD0_BITER_ELINKNO = UART_Buffer_Size; DMA_TCD1_BITER_ELINKNO = UART_Buffer_Size; // Reset buffer when full DMA_TCD0_DLASTSGA = -( UART_Buffer_Size ); DMA_TCD1_DLASTSGA = -( UART_Buffer_Size ); // Enable DMA channels DMA_ERQ |= DMA_ERQ_ERQ0 | DMA_ERQ_ERQ1; // Setup DMA channel routing DMAMUX0_CHCFG0 = DMAMUX_ENABLE | DMAMUX_SOURCE_UART0_RX; DMAMUX0_CHCFG1 = DMAMUX_ENABLE | DMAMUX_SOURCE_UART1_RX; // Enable DMA requests (requires Rx interrupts) UART0_C5 = UART_C5_RDMAS; UART1_C5 = UART_C5_RDMAS; // TX Enabled, RX Enabled, RX Interrupt Enabled UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE; UART1_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE; // Add interrupts to the vector table NVIC_ENABLE_IRQ( IRQ_UART0_STATUS ); NVIC_ENABLE_IRQ( IRQ_UART1_STATUS ); // UARTs are now ready to go uarts_configured = 1; // Reset the state of the UART variables Connect_reset(); }
/******************************************************************************* * Enable digital interrupt and configure the pin *******************************************************************************/ void SnoozeDigital::enableDriver( void ) { if ( mode == RUN_LP ) { return; } #if defined(KINETISK) uint64_t _pin = pin; isr_pin = pin; if ( mode == VLPW || mode == VLPS ) { return_isr_a_enabled = NVIC_IS_ENABLED( IRQ_PORTA ); return_isr_b_enabled = NVIC_IS_ENABLED( IRQ_PORTB ); return_isr_c_enabled = NVIC_IS_ENABLED( IRQ_PORTC ); return_isr_d_enabled = NVIC_IS_ENABLED( IRQ_PORTD ); return_isr_e_enabled = NVIC_IS_ENABLED( IRQ_PORTE ); NVIC_DISABLE_IRQ(IRQ_PORTA); NVIC_DISABLE_IRQ(IRQ_PORTB); NVIC_DISABLE_IRQ(IRQ_PORTC); NVIC_DISABLE_IRQ(IRQ_PORTD); NVIC_DISABLE_IRQ(IRQ_PORTE); NVIC_CLEAR_PENDING(IRQ_PORTA); NVIC_CLEAR_PENDING(IRQ_PORTB); NVIC_CLEAR_PENDING(IRQ_PORTC); NVIC_CLEAR_PENDING(IRQ_PORTD); NVIC_CLEAR_PENDING(IRQ_PORTE); int priority = nvic_execution_priority( );// get current priority // if running from interrupt set priority higher than current interrupt priority = ( priority < 256 ) && ( ( priority - 16 ) > 0 ) ? priority - 16 : 128; return_priority_a = NVIC_GET_PRIORITY( IRQ_PORTA );//get current priority return_priority_b = NVIC_GET_PRIORITY( IRQ_PORTB );//get current priority return_priority_c = NVIC_GET_PRIORITY( IRQ_PORTC );//get current priority return_priority_d = NVIC_GET_PRIORITY( IRQ_PORTD );//get current priority return_priority_e = NVIC_GET_PRIORITY( IRQ_PORTE );//get current priority NVIC_SET_PRIORITY( IRQ_PORTA, priority );//set priority to new level NVIC_SET_PRIORITY( IRQ_PORTB, priority );//set priority to new level NVIC_SET_PRIORITY( IRQ_PORTC, priority );//set priority to new level NVIC_SET_PRIORITY( IRQ_PORTD, priority );//set priority to new level NVIC_SET_PRIORITY( IRQ_PORTE, priority );//set priority to new level __disable_irq( ); return_porta_irq = _VectorsRam[IRQ_PORTA+16];// save prev isr handler return_portb_irq = _VectorsRam[IRQ_PORTB+16];// save prev isr handler return_portc_irq = _VectorsRam[IRQ_PORTC+16];// save prev isr handler return_portd_irq = _VectorsRam[IRQ_PORTD+16];// save prev isr handler return_porte_irq = _VectorsRam[IRQ_PORTE+16];// save prev isr handler attachInterruptVector( IRQ_PORTA, isr );// set snooze digA isr attachInterruptVector( IRQ_PORTB, isr );// set snooze digB isr attachInterruptVector( IRQ_PORTC, isr );// set snooze digC isr attachInterruptVector( IRQ_PORTD, isr );// set snooze digD isr attachInterruptVector( IRQ_PORTE, isr );// set snooze digE isr __enable_irq( ); NVIC_ENABLE_IRQ( IRQ_PORTA ); NVIC_ENABLE_IRQ( IRQ_PORTB ); NVIC_ENABLE_IRQ( IRQ_PORTC ); NVIC_ENABLE_IRQ( IRQ_PORTD ); NVIC_ENABLE_IRQ( IRQ_PORTE ); } _pin = pin; while ( __builtin_popcountll( _pin ) ) { uint32_t pinNumber = 63 - __builtin_clzll( _pin );// get pin if ( pinNumber > 33 ) break; uint32_t pin_mode = irqType[pinNumber] >> 4;// get type uint32_t pin_type = irqType[pinNumber] & 0x0F;// get mode volatile uint32_t *config; config = portConfigRegister( pinNumber ); return_core_pin_config[pinNumber] = *config; if ( pin_mode == INPUT || pin_mode == INPUT_PULLUP ) {// setup pin mode/type/interrupt *portModeRegister( pinNumber ) = 0; if ( pin_mode == INPUT ) *config = PORT_PCR_MUX( 1 ); else *config = PORT_PCR_MUX( 1 ) | PORT_PCR_PE | PORT_PCR_PS;// pullup if ( mode == VLPW || mode == VLPS ) { attachDigitalInterrupt( pinNumber, pin_type );// set pin interrupt } else { llwu_configure_pin_mask( pinNumber, mode ); } } else { //pinMode( pinNumber, pin_mode ); //digitalWriteFast( pinNumber, pin_type ); } _pin &= ~( ( uint64_t )1 << pinNumber );// remove pin from list } #elif defined(KINETISL) uint32_t _pin = pin; isr_pin = pin; if ( mode == VLPW || mode == VLPS ) {// if using sleep must setup pin interrupt to wake return_isr_a_enabled = NVIC_IS_ENABLED( IRQ_PORTA ); return_isr_cd_enabled = NVIC_IS_ENABLED( IRQ_PORTCD ); NVIC_DISABLE_IRQ(IRQ_PORTA); NVIC_DISABLE_IRQ(IRQ_PORTCD); NVIC_CLEAR_PENDING(IRQ_PORTA); NVIC_CLEAR_PENDING(IRQ_PORTCD); int priority = nvic_execution_priority( );// get current priority // if running from interrupt set priority higher than current interrupt priority = ( priority < 256 ) && ( ( priority - 16 ) > 0 ) ? priority - 16 : 128; return_priority_a = NVIC_GET_PRIORITY( IRQ_PORTA );//get current priority return_priority_cd = NVIC_GET_PRIORITY( IRQ_PORTCD );//get current priority NVIC_SET_PRIORITY( IRQ_PORTA, priority );//set priority to new level NVIC_SET_PRIORITY( IRQ_PORTCD, priority );//set priority to new level __disable_irq( ); return_porta_irq = _VectorsRam[IRQ_PORTA+16];// save prev isr handler return_portcd_irq = _VectorsRam[IRQ_PORTCD+16];// save prev isr handler attachInterruptVector( IRQ_PORTA, isr );// set snooze isr attachInterruptVector( IRQ_PORTCD, isr );// set snooze isr __enable_irq( ); NVIC_ENABLE_IRQ( IRQ_PORTA ); NVIC_ENABLE_IRQ( IRQ_PORTCD ); } _pin = pin; while ( __builtin_popcount( _pin ) ) { uint32_t pinNumber = 31 - __builtin_clz( _pin );// get pin if ( pinNumber > 33 ) break; uint32_t pin_mode = irqType[pinNumber] >> 4;// get type uint32_t pin_type = irqType[pinNumber] & 0x0F;// get mode volatile uint32_t *config; config = portConfigRegister( pinNumber ); return_core_pin_config[pinNumber] = *config; if ( pin_mode == INPUT || pin_mode == INPUT_PULLUP ) {// setup pin mode/type/interrupt *portModeRegister( pinNumber ) &= ~digitalPinToBitMask( pinNumber ); // TODO: atomic if ( pin_mode == INPUT ) *config = PORT_PCR_MUX( 1 ); else *config = PORT_PCR_MUX( 1 ) | PORT_PCR_PE | PORT_PCR_PS;// pullup if ( pin_mode == VLPW || pin_mode == VLPS ) { attachDigitalInterrupt( pinNumber, pin_type );// set pin interrupt } else { llwu_configure_pin_mask( pinNumber, pin_mode ); } } else { //pinMode( pinNumber, pin_mode ); //digitalWriteFast( pinNumber, pin_type ); } _pin &= ~( ( uint32_t )1 << pinNumber );// remove pin from list } #endif }
void OctoWS2811::begin(void) { uint32_t frequency; // set up the buffers memset(frameBuffer[0], 0, bufSize); memset(frameBuffer[1], 0, bufSize); // configure the 8 output pins GPIOD_PCOR = 0xFF; pinMode(2, OUTPUT); // strip #1 pinMode(14, OUTPUT); // strip #2 pinMode(7, OUTPUT); // strip #3 pinMode(8, OUTPUT); // strip #4 pinMode(6, OUTPUT); // strip #5 pinMode(20, OUTPUT); // strip #6 pinMode(21, OUTPUT); // strip #7 pinMode(5, OUTPUT); // strip #8 #ifdef TWOPORT #ifdef C8SYNC //don't use pin 15-16 loopback, use something else. You still pretty much need to use pin16 as it has FTM1_CH0 muxed on it. Instead of B0 you could also use A12 (see datasheet) GPIOC_PCOR = 0xFF; pinMode(28, OUTPUT); // C8(pin28) -> B0 for sync instead of C0-B0 to free up C0 for an extra LED strip. #else //reserve C0 for pwm (this is default setup of the Octo2811 buffer board, but you can't use C0 for strip output so you only get 15 usable channels) GPIOC_PCOR = 0xFE; #endif pinMode(22, OUTPUT); // PC1 strip #9 pinMode(23, OUTPUT); // PC2 strip #10 pinMode(9, OUTPUT); // PC3 strip #11 pinMode(10, OUTPUT); // PC4 strip #12 pinMode(13, OUTPUT); // PC5 strip #13 pinMode(11, OUTPUT); // PC6 strip #14 pinMode(12, OUTPUT); // PC7 strip #15 #endif #ifdef DEBUGSYNC pinMode(0, OUTPUT); // B16 sync for scope testing #endif // create the two waveforms for WS2811 low and high bits frequency = 800000; analogWriteResolution(8); analogWriteFrequency(3, frequency); analogWriteFrequency(4, frequency); analogWrite(3, WS2811_TIMING_T0H); analogWrite(4, WS2811_TIMING_T1H); #ifdef C8SYNCxxxxx // Optionally use A12 (pin 3) instead of B0 - triggers DMA(port B) on rising edge (configure for pin 3's waveform) #else // pin 16 (b0) is FTM1_CH0, triggers DMA(port B) on rising edge (configure mux to output pin 3's waveform) CORE_PIN16_CONFIG = PORT_PCR_IRQC(1)|PORT_PCR_MUX(3); //pin35 (B0) , mux to FTM1_CH0 IRQC0001 = DMA on rising edge pinMode(3, INPUT_PULLUP); // pin 3 (A12, configured by the AnalogWrite(3..) above is no longer needed for PWM so set as input or whatever you like #endif #ifdef C8SYNC // pin 28 (C8) triggers DMA(port C) on falling edge of low duty waveform // pin 28 and 25 must be connected by the user: 25 is output, 28 is input pinMode(28, INPUT); //c8 //PTC8 input, IRQC0010 = DMA on rising edge CORE_PIN28_CONFIG = PORT_PCR_IRQC(2)|PORT_PCR_MUX(1); #else // pin 15 (C0) triggers DMA(port C) on falling edge of low duty waveform // pin 15 and 16 must be connected by the user: 16 is output, 15 is input pinMode(15, INPUT); //c0 //pin43 = PTC0 input, IRQC0010 = DMA on rising edge CORE_PIN15_CONFIG = PORT_PCR_IRQC(2)|PORT_PCR_MUX(1); #endif // pin 4 triggers DMA(port A) on falling edge of high duty waveform //pin29 = (A13) mux to FTM1_CH1 IRQC0010=DMA on falling edge CORE_PIN4_CONFIG = PORT_PCR_IRQC(2)|PORT_PCR_MUX(3); // enable clocks to the DMA controller and DMAMUX SIM_SCGC7 |= SIM_SCGC7_DMA; SIM_SCGC6 |= SIM_SCGC6_DMAMUX; DMA_CR = 0; DMA_ERQ = 0; // DMA channel #1 sets WS2811 high at the beginning of each cycle #ifndef TWOPORT //original octo2811 8-channel DMA setup DMA_TCD1_SADDR = &ones; DMA_TCD1_SOFF = 0; DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); DMA_TCD1_NBYTES_MLNO = 1; DMA_TCD1_SLAST = 0; DMA_TCD1_DADDR = &GPIOD_PSOR; DMA_TCD1_DOFF = 0; DMA_TCD1_CITER_ELINKNO = bufSize; DMA_TCD1_DLASTSGA = 0; DMA_TCD1_CSR = DMA_TCD_CSR_DREQ; DMA_TCD1_BITER_ELINKNO = bufSize; // DMA channel #2 writes the pixel data at 20% of the cycle DMA_TCD2_SADDR = frameBuffer[1]; DMA_TCD2_SOFF = 1; DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); DMA_TCD2_NBYTES_MLNO = 1; DMA_TCD2_SLAST = -bufSize; DMA_TCD2_DADDR = &GPIOD_PDOR; DMA_TCD2_DOFF = 0; DMA_TCD2_CITER_ELINKNO = bufSize; DMA_TCD2_DLASTSGA = 0; DMA_TCD2_CSR = DMA_TCD_CSR_DREQ; DMA_TCD2_BITER_ELINKNO = bufSize; // DMA channel #3 clear all the pins low at 48% of the cycle DMA_TCD3_SADDR = &ones; DMA_TCD3_SOFF = 0; DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); DMA_TCD3_NBYTES_MLNO = 1; DMA_TCD3_SLAST = 0; DMA_TCD3_DADDR = &GPIOD_PCOR; DMA_TCD3_DOFF = 0; DMA_TCD3_CITER_ELINKNO = bufSize; DMA_TCD3_DLASTSGA = 0; DMA_TCD3_CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR; DMA_TCD3_BITER_ELINKNO = bufSize; #else //DrTune's 16-channel DMA setup //0x40 byte address gap between sequential ports (a,b,c,d) #define PORT_SPACING 0x40 /*between ports C and D */ #define MLOFFYES (1+1) // 2 byte tranfers per minor loop (port C then D) #define FREEZE_DEST_ADDR_BITS 7 /*force dest address to alternate between ports C+D */ DMA_CR = (1<<7); //EMLM minor loop enabled; //write port C and D in a minor loop DMA_TCD1_SADDR = &ones; DMA_TCD1_SOFF = 0; DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3); DMA_TCD1_NBYTES_MLOFFYES = MLOFFYES; DMA_TCD1_SLAST = 0; DMA_TCD1_DADDR = &GPIOC_PSOR; DMA_TCD1_DOFF = PORT_SPACING; DMA_TCD1_CITER_ELINKNO = bufSize/2; DMA_TCD1_DLASTSGA = 0; DMA_TCD1_CSR = DMA_TCD_CSR_DREQ; DMA_TCD1_BITER_ELINKNO = bufSize/2; // DMA channel #2 writes the pixel data at 20% of the cycle DMA_TCD2_SADDR = frameBuffer[1]; DMA_TCD2_SOFF = 1; DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3);; DMA_TCD2_NBYTES_MLOFFYES = MLOFFYES; DMA_TCD2_SLAST = -bufSize; DMA_TCD2_DADDR = &GPIOC_PDOR; DMA_TCD2_DOFF = PORT_SPACING; DMA_TCD2_CITER_ELINKNO = bufSize/2; DMA_TCD2_DLASTSGA = 0; DMA_TCD2_CSR = DMA_TCD_CSR_DREQ; DMA_TCD2_BITER_ELINKNO = bufSize/2; // DMA channel #3 clear all the pins low at 48% of the cycle DMA_TCD3_SADDR = &ones; DMA_TCD3_SOFF = 0; DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0) | (FREEZE_DEST_ADDR_BITS<<3);; DMA_TCD3_NBYTES_MLOFFYES = MLOFFYES; DMA_TCD3_SLAST = 0; DMA_TCD3_DADDR = &GPIOC_PCOR; DMA_TCD3_DOFF = PORT_SPACING; DMA_TCD3_CITER_ELINKNO = bufSize/2; DMA_TCD3_DLASTSGA = 0; DMA_TCD3_CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR; DMA_TCD3_BITER_ELINKNO = bufSize/2; #endif #ifdef __MK20DX256__ MCM_CR = MCM_CR_SRAMLAP(1) | MCM_CR_SRAMUAP(0); AXBS_PRS0 = 0x1032; #endif // route the edge detect interrupts to trigger the 3 channels DMAMUX0_CHCFG1 = 0; DMAMUX0_CHCFG1 = DMAMUX_SOURCE_PORTB | DMAMUX_ENABLE; DMAMUX0_CHCFG2 = 0; DMAMUX0_CHCFG2 = DMAMUX_SOURCE_PORTC | DMAMUX_ENABLE; DMAMUX0_CHCFG3 = 0; DMAMUX0_CHCFG3 = DMAMUX_SOURCE_PORTA | DMAMUX_ENABLE; // enable a done interrupts when channel #3 completes NVIC_ENABLE_IRQ(IRQ_DMA_CH3); //pinMode(1, OUTPUT); // testing: oscilloscope trigger }
// ------------------------------------------------------------ // this function initializes and starts the timer, using the specified // function as a callback. must be passed the name of a function taking // no arguments and returning void. make sure this function can // complete within the time allowed (aka less than its period) // ------------------------------------------------------------ void PITimer::start(void (*newISR)()) { myISR = newISR; isRunning = true; *PIT_TCTRL = 3; NVIC_ENABLE_IRQ(IRQ_PIT_CH); }
/* Enable interrupts: An ADC Interrupt will be raised when the conversion is completed * (including hardware averages and if the comparison (if any) is true). */ void ADC::enableInterrupts() { var_enableInterrupts = 1; NVIC_ENABLE_IRQ(IRQ_ADC0); }