/** * @brief SPI DMA Transfer * NULL can be input as txBuffer if tx data to transmit dummy data * If only sending data, set rxBuffer as NULL to skip DMA activation on RX */ void spiDmaTransfer(void *txBuffer, void *rxBuffer, int bytes) { /* Only activate RX DMA if a receive buffer is specified */ if (rxBuffer != NULL) { /* Setting flag to indicate that RX is in progress * will be cleared by call-back function */ rxActive = true; /* Clear RX regiters */ USART2->CMD = USART_CMD_CLEARRX; /* Activate RX channel */ DMA_ActivateBasic(DMA_CHANNEL_RX, true, false, rxBuffer, (void *)&(USART2->RXDATA), bytes - 1); } /* Setting flag to indicate that TX is in progress * will be cleared by call-back function */ txActive = true; /* Clear TX regsiters */ USART2->CMD = USART_CMD_CLEARTX; /* Activate TX channel */ DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(USART2->TXDATA), txBuffer, bytes - 1); }
/* *Function name: LEUART0_IRQHandler *Description : Interrupt Service Routine for LEUART0. */ void LEUART0_IRQHandler(void) { leuartif = LEUART_IntGet(LEUART0); // Store the interrupt flag LEUART_IntClear(LEUART0, leuartif); //Clear interrupts if (leuartif & LEUART_IF_SIGF) { int temp = 0, i = 0; char tempChar[7]; // To store the Value of Temperature in char to transmit char temp_string[TX_bufferSize]; // Concatenated string for Message and Temperature, this will be transfered char copyCmp[sizeof(commandString)/sizeof(char)]; // string to store the Received string from Buffer to compare // Stop the LEUART reception and DMA Transfers for (i = 0; i < (strlen(commandString)); i++) // Run loop till the return message (RetTemp!) length and copy RX buffer to copyCmp for comparing { copyCmp[i] = RX_Buffer[i]; } copyCmp[8]='\0'; /* To extract the digits of the temperature variable and put in tempChar. A basic digit extraction algorithm is used and then each digit is passed one by one. */ if (!strcmp(commandString,copyCmp)) // If valid Command is Received ie RetTemp! { temp = temperature*10; tempChar[0] = (temp/100)+48; temp = temp%100; tempChar[1] = (temp/10)+48; temp = temp%10; tempChar[2] = '.'; tempChar[3] = (temp)+48; tempChar[4] = 'C'; tempChar[5] = '\r'; tempChar[6] = '\n'; strcpy(temp_string,returnMsg); //Copy the returnMsg message in the temporary string strcat(temp_string,tempChar); // Concatenate with tempChar to get the final message to be transfered // Enable DMA wake-up from LEUART0 TX LEUART0->CTRL = LEUART_CTRL_TXDMAWU; // Enable DMA wake up for LEUART TX in EM2 // Activate DMA for LEUART TX transfers DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(LEUART0->TXDATA), (void *)temp_string, strlen(temp_string)- 1); // -1 for the Null character which we wont transmit } else { LEUART0->CTRL = LEUART_CTRL_TXDMAWU; // Enable DMA wake up for LEUART0 TX in EM2 // Activate DMA for LEUART TX transfers DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(LEUART0->TXDATA), (void *)errorMsg, strlen(errorMsg)-2); // -1 for the Null character which we wont transmit } LEUART_IntEnable(LEUART0, LEUART_IF_RXDATAV); //Enable RXDATA Interrupt to check for received characters DMA_ActivateBasic(DMA_CHANNEL_RX, true, false, NULL, NULL, LEUART0_BUFFER-1); } else if (leuartif & LEUART_IF_RXDATAV) { LEUART_IntDisable(LEUART0, LEUART_IF_RXDATAV); // Disable after receiving } }
/**************************************************************************//** * @brief SPI DMA Transfer * NULL can be input as txBuffer if tx data to transmit dummy data * If only sending data, set rxBuffer as NULL to skip DMA activation on RX. * AUTOTX is used instead of DMA TX channel if txBuffer is NULL *****************************************************************************/ void spiDmaTransfer(uint8_t *txBuffer, uint8_t *rxBuffer, int bytes) { /* Use AUTOTX if MOSI data is irrelevant (reading from slave) */ autoTx = (txBuffer == NULL); /* Only activate RX DMA if a receive buffer is specified */ if (rxBuffer != NULL) { /* Setting flag to indicate that RX is in progress * will be cleared by call-back function */ rxActive = true; /* Clear RX registers */ USART1->CMD = USART_CMD_CLEARRX; /* Activate RX channel */ DMA_ActivateBasic(DMA_CHANNEL_RX, true, false, rxBuffer, (void *)&(USART1->RXDATA), bytes - (autoTx ? 4 : 1)); /* Skip last 3 bytes if AUTOTX is used */ } /* Clear TX registers */ USART1->CMD = USART_CMD_CLEARTX; /* Setting flag to indicate that TX is in progress * will be cleared by callback function or USART RX interrupt (if using AUTOTX) */ txActive = true; /* Activate AUTOTX when only reading from slave. If using TX data from a * buffer use a TX DMA channel */ if (autoTx) { rxBufferG = (uint8_t *) rxBuffer; /* Copy buffer pointer to global variable */ /* Setting AUTOTX will start TX as long as there is room in RX registers */ USART1->CTRL |= USART_CTRL_AUTOTX; } else { /* Activate TX channel */ DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(USART1->TXDATA), txBuffer, bytes - 1); } }
void dmaStartFrameTransfer(int firstLine, int lastLine) { /* Get address of first line */ uint16_t *startAddr = FB_getActiveBuffer(); startAddr += firstLine * 10; /* Create update command and address of first line */ uint16_t cmd = MEMLCD_CMD_UPDATE | ((firstLine+1) << 8); /* Enable chip select */ GPIO_PinOutSet( pConf->scs.port, pConf->scs.pin ); /* Set number of lines to copy */ DMA->RECT0 = (DMA->RECT0 & ~_DMA_RECT0_HEIGHT_MASK) | (lastLine - firstLine); /* Indicate to the rest of the program that SPI transfer is in progress */ spiTransferActive = true; /* Send the update command */ USART_TxDouble(pConf->usart, cmd); /* Start the transfer */ DMA_ActivateBasic(DMA_CHANNEL, true, /* Use primary channel */ false, /* No burst */ (void *)&(pConf->usart->TXDOUBLE), /* Write to USART */ startAddr, /* Start address */ FRAME_BUFFER_WIDTH/16-1); /* Width -1 */ }
/***************************************************************************** * @brief Reads from I2C EEPROM using DMA. * * @param deviceAddress * I2C address of EEPROM * * @param offset * The offset (address) to start reading from * * @param data * Pointer to the data buffer * * @param length * Number of bytes to read *****************************************************************************/ void i2cDmaRead(uint8_t deviceAddress, uint8_t offset, uint8_t *data, uint8_t length) { /* Wait for any previous transfer to finish */ while ( transferActive ) { EMU_EnterEM1(); } /* Abort if an error has occured */ if ( i2cError ) { return; } /* Clear all pending interrupts prior to starting transfer. */ I2C0->IFC = _I2C_IFC_MASK; /* Write address to read from. Note that this is specific to the EEPROM on the * EFM32GG-DK3750 and may need to be changed when using a different device. */ i2cWriteByte(deviceAddress, offset); /* Send the device address. I2C_CMD_START must be written before * TXDATA since this is a repeated start. */ I2C0->CMD = I2C_CMD_START; I2C0->TXDATA = deviceAddress | I2C_READ_BIT; /* Wait for ACK on the address */ if ( !i2cWaitForAckNack() ) { i2cErrorAbort(); return; } /* Do not start DMA if an error has occured */ if ( i2cError ) { return; } /* Automatically ACK received bytes */ I2C0->CTRL |= I2C_CTRL_AUTOACK; /* These are used by the RX interrupt handler * to fetch the last two bytes of the transaction */ rxPointer = data + length - 2; bytesLeft = 2; /* Set transfer active flag. Cleared by interrupt handler * when STOP condition has been sent. */ transferActive = true; /* Activate DMA */ DMA_ActivateBasic(DMA_CHANNEL_I2C_RX, /* RX DMA channel */ true, /* Primary descriptor */ false, /* No burst */ (void *)data, /* Write to rx buffer */ (void *)&(I2C0->RXDATA), /* Read from RXDATA */ length - 3 ); /* Number of transfers */ }
/* * Function Name: main(); * Description: All the function calls are done in main(). The CPU goes to sleep while in main(); until Interupt is generated. */ int main(void) { CHIP_Init(); CMU_HFRCOBandSet(cmuHFRCOBand_14MHz); CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO); CMU_OscillatorEnable(cmuOsc_HFXO, false, false); blockSleepMode(EM2); //Prevents the CPU to go below EM3 mode. #if DEBUG_ON BSP_TraceSwoSetup(); //For simplicity studio Energy profiler code correlation. #endif LETIMER_setup(); //Initialize LETIMER. ADC_Setup(); //Initialize the ADC DMA_Init(); //Initialize DMA. DMA_Setup(); //Setup DMA. LEUART_Setup(); //Initialize LEUART. GPIO_Init(); //Initialize GPOIs. LETIMER_IntEnable(LETIMER0, LETIMER_IF_UF); //Enable underflow UF interrupt. LEUART_IntEnable(LEUART0, LEUART_IF_SIGF); // Enable SF RXDATAV NVIC_EnableIRQ(LETIMER0_IRQn); //Enable LETIMER0 interrupt vector in NVIC (Nested Vector Interrupt Controller) NVIC_EnableIRQ(LEUART0_IRQn); //Enable LETIMER0 interrupt vector in NVIC (Nested Vector Interrupt Controller) LEUART0->SIGFRAME = '!'; // Set LEUART signal frame to '!' LEUART0->CTRL |= LEUART_CTRL_RXDMAWU; // Enable DMA wake up for LEUART RX in EM2 DMA_ActivateBasic(DMA_CHANNEL_RX, true, false, (void *)RX_Buffer, (void *)&(LEUART0->RXDATA), LEUART0_BUFFER-1); // Enable Sleep-on-Exit #if SLEEPONEXIT SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // Setting the corresponding bit for SleepOnExit #endif while(1) { sleep(); //CPU goes to EM3 Mode to save energy, waits there until Interrupt is generated. } }
/* * Function Name: ADC_setup * Description: Configures ADC0 */ void LEUART_Setup(void) { /* Enabling the required clocks */ CMU_ClockEnable(cmuClock_LFB, true); //Enable the clock input to LETIMER CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); //Selecting the ULFRCO as the source clock CMU_ClockEnable(cmuClock_LEUART0, true); //Enable the clock input to LETIMER /* Defining the LEUART1 initialization data */ LEUART_Init_TypeDef leuart0Init = { .enable = leuartEnable, // Activate data reception on LEUn_TX pin. .refFreq = 0, // Inherit the clock frequency from the LEUART clock source .baudrate = LEUART0_BAUD, // Baudrate = 9600 bps .databits = LEUART0_Databits, // Each LEUART frame contains 8 databits .parity = LEUART0_Parity, // No parity bits in use .stopbits = LEUART0_Stopbits, // Setting the number of stop bits in a frame to 2 bitperiods }; LEUART_Init(LEUART0, &leuart0Init); // Route LEUART1 TX,RX pin to DMA location 0 LEUART0->ROUTE = LEUART_ROUTE_TXPEN | LEUART_ROUTE_RXPEN | LEUART_ROUTE_LOCATION_LOC0; // Enable GPIO for LEUART1. TX is on D4 GPIO_PinModeSet(gpioPortD, 4, gpioModePushPull, 0); // Enable GPIO for LEUART1. RX is on D5 GPIO_PinModeSet(gpioPortD, 5, gpioModeInputPull, 0); // Pull PD15(CTS pin of BLE module) to GRND GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 0); } /* *Function name: LETIMER0_IRQHandler *Description : Interrupt Service Routine for LETIMER. */ void LETIMER0_IRQHandler(void) { LETIMER_IntClear(LETIMER0, LETIMER_IF_UF); //Clear LETIMER0 underflow (UF) and COMP1 flag. DMA_ActivateBasic(DMA_CHANNEL_ADC, true, false, (void *)ADC_Buffer, (void *)&(ADC0->SINGLEDATA), ADC_SAMPLES - 1); ADC_Setup(); // ADC start ADC_Start(ADC0, adcStartSingle); unblockSleepMode(EM2); blockSleepMode(EM1); trfComplete=false; }
/**************************************************************************//** * @brief Flash transfer function * This function sets up the DMA transfer *****************************************************************************/ void performFlashTransfer(void) { /* Setting call-back function */ DMA_CB_TypeDef cb[DMA_CHAN_COUNT]; cb[DMA_CHANNEL_FLASH].cbFunc = flashTransferComplete; /* usrPtr can be used to send data to the callback function, * but this is not used here, which is indicated by the NULL pointer */ cb[DMA_CHANNEL_FLASH].userPtr = NULL; /* Setting up channel */ DMA_CfgChannel_TypeDef chnlCfg; chnlCfg.highPri = false; chnlCfg.enableInt = true; chnlCfg.select = 0; chnlCfg.cb = &(cb[DMA_CHANNEL_FLASH]); DMA_CfgChannel(DMA_CHANNEL_FLASH, &chnlCfg); /* Setting up channel descriptor */ DMA_CfgDescr_TypeDef descrCfg; descrCfg.dstInc = dmaDataInc1; descrCfg.srcInc = dmaDataInc1; descrCfg.size = dmaDataSize1; descrCfg.arbRate = dmaArbitrate1; descrCfg.hprot = 0; DMA_CfgDescr(DMA_CHANNEL_FLASH, true, &descrCfg); /* Setting flag to indicate that transfer is in progress * will be cleared by call-back function */ flashTransferActive = true; DMA_ActivateBasic(DMA_CHANNEL_FLASH, true, false, (void *) &ramBuffer, (void *) &flashData, FLASHDATA_SIZE - 1); /* Entering EM1 to wait for completion (the DMA requires EM1) */ while (flashTransferActive) { EMU_EnterEM1(); } }
/**************************************************************************//** * @brief Configure DMA for ADC RAM Transfer *****************************************************************************/ void setupDma(void) { DMA_Init_TypeDef dmaInit; DMA_CfgChannel_TypeDef chnlCfg; DMA_CfgDescr_TypeDef descrCfg; /* Initializing the DMA */ dmaInit.hprot = 0; dmaInit.controlBlock = dmaControlBlock; DMA_Init(&dmaInit); /* Setting up call-back function */ cb.cbFunc = transferComplete; cb.userPtr = NULL; /* Setting up channel */ chnlCfg.highPri = false; chnlCfg.enableInt = true; chnlCfg.select = DMAREQ_ADC0_SINGLE; chnlCfg.cb = &cb; DMA_CfgChannel(DMA_CHANNEL_ADC, &chnlCfg); /* Setting up channel descriptor */ descrCfg.dstInc = dmaDataInc2; descrCfg.srcInc = dmaDataIncNone; descrCfg.size = dmaDataSize2; descrCfg.arbRate = dmaArbitrate1; descrCfg.hprot = 0; DMA_CfgDescr(DMA_CHANNEL_ADC, true, &descrCfg); /* Setting flag to indicate that transfer is in progress * will be cleared by call-back function. */ transferActive = true; /* Starting transfer. Using Basic since every transfer must be initiated * by the ADC. */ DMA_ActivateBasic(DMA_CHANNEL_ADC, true, false, (void *)ramBufferAdcData, (void *)&(ADC0->SINGLEDATA), ADCSAMPLES - 1); }
/***************************************************************************** * @brief Writes bytes to I2C EEPROM using DMA. * * @param deviceAddress * I2C address of EEPROM * * @param offset * The offset (address) to start writing from * * @param data * Pointer to the data buffer * * @param length * Number of bytes to write *****************************************************************************/ void i2cDmaWrite(uint8_t deviceAddress, uint8_t offset, uint8_t *data, uint8_t length) { /* Abort if an error has been detected */ if ( i2cError ) { return; } /* Send address to write to. Note that this is specific to the EEPROM on the * EFM32GG-DK3750 and may need to be changed when using a different device. */ i2cWriteByte(deviceAddress, offset); /* Abort if an error has been detected */ if ( i2cError ) { return; } /* Automatically generate a STOP condition when there is no * more data to send. The DMA must be fast enough to * keep up (normally not a problem unless the DMA is * been prescaled). */ I2C0->CTRL |= I2C_CTRL_AUTOSE; /* Set transfer active flag. Cleared by interrupt handler * when STOP condition has been sent. */ transferActive = true; /* Activate DMA */ DMA_ActivateBasic(DMA_CHANNEL_I2C_TX, /* TX DMA channel */ true, /* Primary descriptor */ false, /* No burst */ (void *)&(I2C0->TXDATA), /* Write to TXDATA */ (void *)data, /* Read from txBuffer */ length - 1 ); /* Number of transfers */ }
/* *Function name: DMA_CallBack() *Description : Call back function of the DMA */ void DMA_CallBack(unsigned int channel, bool primary, void *user) { unblockSleepMode(EM1); blockSleepMode(EM2); if(!trfComplete) { ADC_Reset(ADC0); // Reset the ADC; Turn it off //ADC0->CMD = ADC_CMD_SINGLESTOP; int temp = 0, i = 0; char tempChar[7]; //To store the temperature in char, for transmitting char temp_string[TX_bufferSize]; (void) channel; (void) primary; (void) user; for (i = 0; i < ADC_SAMPLES; i++) { temp += (ADC_Buffer[i]); } temperature = temp / ADC_SAMPLES; temperature = convertToCelsius(temperature); //Get value of Temperature in deg C if (temperature > HIGHTEMP) { //GPIO_PinOutClear(gpioPortE,2); //GPIO_PinOutSet(gpioPortE,3); /* To extract the digits of the temperature variable and put in tempChar. A basic digit extraction algorithm is used and then each digit is passed one by one. */ temp = temperature*10; tempChar[0] = (temp/100)+48; temp = temp%100; tempChar[1] = (temp/10)+48; temp = temp%10; tempChar[2] = '.'; tempChar[3] = (temp)+48; tempChar[4] = 'C'; // Pad the 4th position of charTemp as C tempChar[5] = '\r'; // Pad carriage return tempChar[6] = '\n'; // Pad line feed strcpy(temp_string,HighTemp); // Copy the HighTemp message in the temporary string strcat(temp_string,tempChar); // Concatenate with the tempChar to get the final message LEUART0->CTRL |= LEUART_CTRL_TXDMAWU; // Enable DMA wake up for LEUART TX in EM2 // Activate DMA transfers for LEUART TX DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(LEUART0->TXDATA), (void *)temp_string, strlen(temp_string) - 1); } else if (temperature < LOWTEMP) { //GPIO_PinOutSet(gpioPortE,2); //GPIO_PinOutClear(gpioPortE,3); temp = temperature*10; tempChar[0] = (temp/100)+48; temp = temp%100; tempChar[1] = (temp/10)+48; temp = temp%10; tempChar[2] = '.'; tempChar[3] = (temp)+48; tempChar[4] = 'C'; tempChar[5] = '\r'; tempChar[6] = '\n'; strcpy(temp_string,LowTemp); // Copy the LowTemp message in the temporary string strcat(temp_string,tempChar); // Concatenate with the tempChar to get the final message LEUART0->CTRL |= LEUART_CTRL_TXDMAWU; // Enable DMA wake up for LEUART TX in EM2 // Activate DMA transfers for LEUART TX DMA_ActivateBasic(DMA_CHANNEL_TX, true, false, (void *)&(LEUART0->TXDATA), (void *)temp_string, strlen(temp_string) -1); } trfComplete=true; } else { (void) channel; (void) primary; (void) user; // Disable DMA wake-up from LEUART1 TX LEUART0->CTRL &= ~LEUART_CTRL_TXDMAWU; } }
/* * Function Name: DMA_setup * Description: Setup DMA channels for ADC,TX,RX */ void DMA_Setup(void) { DMA_CfgChannel_TypeDef chnlCfg_adc; DMA_CfgDescr_TypeDef descrCfg_adc; DMA_CfgChannel_TypeDef chnlCfg_rx; DMA_CfgDescr_TypeDef descrCfg_rx; DMA_CfgChannel_TypeDef chnlCfg_tx; DMA_CfgDescr_TypeDef descrCfg_tx; /* Setting up call-back function */ cb.cbFunc = DMA_CallBack; cb.userPtr = NULL; /* Setting up ADC channel */ chnlCfg_adc.highPri = DMA_PRIORITY_ADC; chnlCfg_adc.enableInt = true; chnlCfg_adc.select = DMAREQ_ADC0_SINGLE; chnlCfg_adc.cb = &cb; DMA_CfgChannel(DMA_CHANNEL_ADC, &chnlCfg_adc); /* Setting up ADC channel descriptor */ descrCfg_adc.dstInc = dmaDataInc2; descrCfg_adc.srcInc = dmaDataIncNone; descrCfg_adc.size = dmaDataSize2; descrCfg_adc.arbRate = DMA_ARBITRATE_ADC; descrCfg_adc.hprot = 0; DMA_CfgDescr(DMA_CHANNEL_ADC, true, &descrCfg_adc); /* Starting DMA transfer using Basic since every transfer must be initiated by the ADC. */ DMA_ActivateBasic(DMA_CHANNEL_ADC, true, false, (void *)ADC_Buffer, (void *)&(ADC0->SINGLEDATA), ADC_SAMPLES - 1); /* Setting up Rx channel */ chnlCfg_rx.highPri = DMA_PRIORITY_RX; chnlCfg_rx.enableInt = true; chnlCfg_rx.select = DMAREQ_LEUART0_RXDATAV; chnlCfg_rx.cb = &cb; DMA_CfgChannel(DMA_CHANNEL_RX, &chnlCfg_rx); /* Setting up Rx channel descriptor */ descrCfg_rx.dstInc = dmaDataInc1; descrCfg_rx.srcInc = dmaDataIncNone; descrCfg_rx.size = dmaDataSize1; descrCfg_rx.arbRate = DMA_ARBITRATE_RX; descrCfg_rx.hprot = 0; DMA_CfgDescr(DMA_CHANNEL_RX, true, &descrCfg_rx); /* Setting up Tx channel */ chnlCfg_tx.highPri = DMA_PRIORITY_TX; chnlCfg_tx.enableInt = true; chnlCfg_tx.select = DMAREQ_LEUART0_TXBL; chnlCfg_tx.cb = &cb; DMA_CfgChannel(DMA_CHANNEL_TX, &chnlCfg_tx); /* Setting up Tx channel descriptor */ descrCfg_tx.dstInc = dmaDataIncNone; descrCfg_tx.srcInc = dmaDataInc1; descrCfg_tx.size = dmaDataSize1; descrCfg_tx.arbRate = DMA_ARBITRATE_TX; descrCfg_tx.hprot = 0; DMA_CfgDescr(DMA_CHANNEL_TX, true, &descrCfg_tx); }
int main(void) { /** Number of samples/channels taken from accelerometer. */ #define ACCEL_SAMPLES 3 /** X axis sample index. */ #define ACCEL_X 0 /** Y axis sample index. */ #define ACCEL_Y 1 /** Z axis sample index. */ #define ACCEL_Z 2 /* * Tilt levels: Midpoint is theoretically half value of max sampling value * (ie 0x800 for 12 bit sampling). In real world, some sort of calibration * is required if more accurate sensing is required. We just use set some * fixed limit, that should be sufficient for this basic example. */ /** Tilt left limit */ #define TILT_LEFT 0x750 /** Tilt right limit */ #define TILT_RIGHT 0x8b0 SYSTEM_ChipRevision_TypeDef chipRev; uint32_t leds; uint32_t samples[ACCEL_SAMPLES]; int errataShift = 0; int i; /* Chip revision alignment and errata fixes */ CHIP_Init(); /* ADC errata for rev B when using VDD as reference, need to multiply */ /* result by 2 */ SYSTEM_ChipRevisionGet(&chipRev); if ((chipRev.major == 1) && (chipRev.minor == 1)) { errataShift = 1; } /* Initialize DK board register access */ BSP_Init(BSP_INIT_DEFAULT); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Connect accelerometer to EFM32. */ BSP_PeripheralAccess(BSP_ACCEL, true); /* Enable clocks required */ CMU_ClockEnable(cmuClock_HFPER, true); CMU_ClockEnable(cmuClock_ADC0, true); CMU_ClockEnable(cmuClock_DMA, true); /* Configure ADC and DMA used for scanning accelerometer */ accelADCConfig(); accelDMAConfig(); /* Main loop, keep polling accelerometer */ leds = 0x0180; while (1) { DMA_ActivateBasic(ACCEL_DMA_CHANNEL, true, false, samples, (void *)((uint32_t)&(ADC0->SCANDATA)), ACCEL_SAMPLES - 1); /* Scan all axis', even though this app only use the X axis */ ADC_IntClear(ADC0, ADC_IF_SCAN); ADC_Start(ADC0, adcStartScan); /* Poll for completion, entering EM2 when waiting for next poll */ while (!(ADC_IntGet(ADC0) & ADC_IF_SCAN)) { RTCDRV_Trigger(5, NULL); EMU_EnterEM2(true); } if (errataShift) { for (i = 0; i < ACCEL_SAMPLES; i++) { samples[i] <<= errataShift; } } if (samples[ACCEL_X] < TILT_LEFT) { if (leds < 0xc000) { leds <<= 1; } } else if (samples[ACCEL_X] > TILT_RIGHT) { if (leds > 0x0003) { leds >>= 1; } } else { if (leds > 0x0180)
/***************************************************************************//** * @brief * Start a UDMA transfer. ******************************************************************************/ static Ecode_t StartTransfer( DmaMode_t mode, DmaDirection_t direction, unsigned int channelId, DMADRV_PeripheralSignal_t peripheralSignal, void *buf0, void *buf1, void *buf2, bool bufInc, int len, DMADRV_DataSize_t size, DMADRV_Callback_t callback, void *cbUserParam ) { ChTable_t *ch; DMA_CfgChannel_TypeDef chCfg; DMA_CfgDescr_TypeDef descrCfg; if ( !initialized ) { return ECODE_EMDRV_DMADRV_NOT_INITIALIZED; } if ( ( channelId > EMDRV_DMADRV_DMA_CH_COUNT ) || ( buf0 == NULL ) || ( buf1 == NULL ) || ( len > DMADRV_MAX_XFER_COUNT ) || ( ( mode == dmaModePingPong ) && ( buf2 == NULL ) ) ) { return ECODE_EMDRV_DMADRV_PARAM_ERROR; } ch = &chTable[ channelId ]; if ( ch->allocated == false ) { return ECODE_EMDRV_DMADRV_CH_NOT_ALLOCATED; } /* Setup the interrupt callback routine. */ if ( mode == dmaModeBasic ) { dmaCallBack[ channelId ].cbFunc = DmaBasicCallback; } else { dmaCallBack[ channelId ].cbFunc = DmaPingPongCallback; } dmaCallBack[ channelId ].userPtr = NULL; /* Setup the channel */ chCfg.highPri = false; /* Can't use hi pri with peripherals. */ /* Interrupt needed ? */ if ( ( callback != NULL ) || ( mode == dmaModePingPong ) ) { chCfg.enableInt = true; } else { chCfg.enableInt = false; } chCfg.select = peripheralSignal; chCfg.cb = &dmaCallBack[ channelId ]; DMA_CfgChannel( channelId, &chCfg ); /* Setup channel descriptor. */ if ( direction == dmaDirectionMemToPeripheral ) { if ( bufInc ) { if ( size == dmadrvDataSize1 ) { descrCfg.srcInc = dmaDataInc1; } else if ( size == dmadrvDataSize2 ) { descrCfg.srcInc = dmaDataInc2; } else /* dmadrvDataSize4 */ { descrCfg.srcInc = dmaDataInc4; } } else { descrCfg.srcInc = dmaDataIncNone; } descrCfg.dstInc = dmaDataIncNone; } else { if ( bufInc ) { if ( size == dmadrvDataSize1 ) { descrCfg.dstInc = dmaDataInc1; } else if ( size == dmadrvDataSize2 ) { descrCfg.dstInc = dmaDataInc2; } else /* dmadrvDataSize4 */ { descrCfg.dstInc = dmaDataInc4; } } else { descrCfg.dstInc = dmaDataIncNone; } descrCfg.srcInc = dmaDataIncNone; } descrCfg.size = (DMA_DataSize_TypeDef)size; descrCfg.arbRate = dmaArbitrate1; descrCfg.hprot = 0; DMA_CfgDescr( channelId, true, &descrCfg ); if ( mode == dmaModePingPong ) { DMA_CfgDescr( channelId, false, &descrCfg ); } ch->callback = callback; ch->userParam = cbUserParam; ch->callbackCount = 0; ch->length = len; DMA->IFC = 1 << channelId; /* Start DMA cycle. */ if ( mode == dmaModeBasic ) { DMA_ActivateBasic( channelId, true, false, buf0, buf1, len - 1 ); } else { if ( direction == dmaDirectionMemToPeripheral ) { DMA_ActivatePingPong( channelId, false, buf0, /* dest */ buf1, /* src */ len - 1, buf0, /* dest */ buf2, /* src */ len - 1); } else { DMA_ActivatePingPong( channelId, false, buf0, /* dest */ buf2, /* src */ len - 1, buf1, /* dest */ buf2, /* src */ len - 1); } } return ECODE_EMDRV_DMADRV_OK; }
/***************************************************************************//** * @brief * Write to USART device * * @details * * @note * * @param[in] dev * Pointer to device descriptor * * @param[in] pos * Offset * * @param[in] buffer * Poniter to the buffer * * @param[in] size * Buffer size in byte * * @return * Number of written bytes ******************************************************************************/ static rt_size_t rt_usart_write ( rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { rt_err_t err_code; struct efm32_usart_device_t* usart = (struct efm32_usart_device_t*)(dev->user_data); rt_size_t read_len, len; rt_uint8_t *ptr; rt_size_t write_size = 0; rt_uint32_t tx_flag, b8_flag; #if defined(UART_PRESENT) if (usart->state & USART_STATE_ASYNC_ONLY) { tx_flag = UART_STATUS_TXBL; b8_flag = UART_CTRL_BIT8DV; } else #endif { tx_flag = USART_STATUS_TXBL; b8_flag = USART_CTRL_BIT8DV; } /* Lock device */ if (rt_hw_interrupt_check()) { err_code = rt_sem_take(usart->lock, RT_WAITING_NO); } else { err_code = rt_sem_take(usart->lock, RT_WAITING_FOREVER); } if (err_code != RT_EOK) { rt_set_errno(err_code); return 0; } if (usart->state & USART_STATE_SYNC) { /* SPI write */ rt_uint8_t inst_len = *((rt_uint8_t *)buffer); rt_uint8_t *inst_ptr = (rt_uint8_t *)(buffer + 1); rt_uint8_t *tx_buf = *((rt_uint8_t **)(buffer + inst_len + 1)); ptr = inst_ptr; len = inst_len; /* Write instructions */ if (len) { if (usart->state & USART_STATE_9BIT) { usart->usart_device->CTRL &= ~b8_flag; } if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (len > 2)) { /* DMA mode Tx */ struct efm32_usart_dma_mode_t *dma_tx; usart_debug("USART: DMA TX INS (%d)\n", len); dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode); dma_tx->data_ptr = (rt_uint32_t *)ptr; dma_tx->data_size = len; usart->state |= USART_STATE_TX_BUSY; DMA_ActivateBasic( dma_tx->dma_channel, true, false, (void *)&(usart->usart_device->TXDATA), (void *)ptr, (rt_uint32_t)(len - 1)); /* Wait, otherwise the TX buffer is overwrite */ // TODO: This function blocks the process => goto low power mode? // if (usart->state & USART_STATE_CONSOLE) // { while(usart->state & USART_STATE_TX_BUSY); // } // else // { // while(usart->state & USART_STATE_TX_BUSY) // { // rt_thread_sleep(USART_WAIT_TIME_TX); // } // } } else { /* polling mode */ usart_debug("USART: Polling TX INS (%d)\n", len); while (len) { while (!(usart->usart_device->STATUS & tx_flag)); usart->usart_device->TXDATA = (rt_uint32_t)*(ptr++); len--; } } if (usart->state & USART_STATE_9BIT) { usart->usart_device->CTRL |= b8_flag; } } ptr = tx_buf; } else { ptr = (rt_uint8_t *)buffer; } len = size; /* Write data */ if (dev->flag & RT_DEVICE_FLAG_STREAM) { if (*(ptr + len - 1) == '\n') { *(ptr + len - 1) = '\r'; *(ptr + len++) = '\n'; *(ptr + len) = 0; } } if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (len > 2)) { /* DMA mode Tx */ struct efm32_usart_dma_mode_t *dma_tx; usart_debug("USART: DMA TX data (%d)\n", len); dma_tx = (struct efm32_usart_dma_mode_t *)(usart->tx_mode); dma_tx->data_ptr = (rt_uint32_t *)ptr; dma_tx->data_size = len; usart->state |= USART_STATE_TX_BUSY; DMA_ActivateBasic( dma_tx->dma_channel, true, false, (void *)&(usart->usart_device->TXDATA), (void *)ptr, (rt_uint32_t)(len - 1)); /* Wait, otherwise the TX buffer is overwrite */ // TODO: This function blocks the process => goto low power mode? // if (usart->state & USART_STATE_CONSOLE) // { while(usart->state & USART_STATE_TX_BUSY); // } // else // { // while(usart->state & USART_STATE_TX_BUSY) // { // rt_thread_sleep(USART_WAIT_TIME_TX); // } // } write_size = size; } else { /* polling mode */ usart_debug("USART: Polling TX data (%d)\n", len); while (len) { while (!(usart->usart_device->STATUS & tx_flag)); usart->usart_device->TXDATA = (rt_uint32_t)*(ptr++); len--; } write_size = size - len; } /* Unlock device */ rt_sem_release(usart->lock); /* set error code */ rt_set_errno(err_code); return write_size; }