This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I made a similar question in another thread but I thought this deserves it's own. I hope I don't anger anyone by doing this.
My goal is to make an external source initiate DMA SPI transfer without waking the MCU up. I am using MSP432 black launchpad(soon red).
I connected my P2.6 GPIO to P7.0 DMAE0 and this is how I want it to work:
I configure the SPI and I enable it. Then I assign channel 0 source to be EUSCIB0_TX and I assign channel 6 source to be EXTERNAL_PIN.
Now I clear the SPI_TX_INTERRUPT flag so my channel 0 won't initate trasnfer as soon as I enable the channel. For both channels the destination is the SPI_TX_BUFFER. And I just tell channel 6 to write 1 byte to TX_BUFFER and when that gets sent the SPI triggers SPI_TX_INTERRUPT which initiates the channel 0 transfer. After that transef completes I want a interrupt to happen to tell me that the transfer completed.
So after I configured the transfers, I enable the interrupt and enable the channel. Now I put high on P2.6(P7.0) and thats the whole application.
The problem is that as soon as I enable the interrupt it occurs even though no transfer happened and I didn't even put high on P2.6. In the documentation it says that the interrupt happens after the DMA completes the transfer. Even if the SPI triggers the DMA interrupt, I cleared the SP_TX_BUFFER and I cleared the DMA_INTERRUPT flag. Here is the code:
//***************************************************************************** // // MSP432 main.c // //**************************************************************************** #include "driverlib.h" #include "IQmathLib.h" #pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024) static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32]; void InitMCU(); void main(void) { InitMCU(); uint8_t buffer = 0x55; // Clear interrupt status SPI_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT); // Activate DMA SPI transfer with external pin DMA_setChannelControl(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1); DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT, UDMA_MODE_BASIC, &buffer, (void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1); // Setup the TX transfer characteristics & buffers DMA_setChannelControl(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1); DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT, UDMA_MODE_BASIC, &buffer, (void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1); MAP_DMA_clearInterruptFlag(0); MAP_DMA_enableInterrupt(INT_DMA_INT1); // Assigning/Enabling Interrupts MAP_Interrupt_enableInterrupt(INT_DMA_INT1); MAP_DMA_enableChannel(0); MAP_DMA_enableChannel(6); GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6); while(1); } // DMA INT1 ISR void DMA_INT1_IRQHandler(void) { return; } // SPI Master Configuration Parameter for CC1200 const eUSCI_SPI_MasterConfig spiMasterConfig = { EUSCI_B_SPI_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 6000000, // SMCLK = HFXT/8 = 6MHz 6000000, // SPICLK = 6MHz EUSCI_B_SPI_MSB_FIRST, // MSB First EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT, // Phase EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Low polarity EUSCI_B_SPI_3PIN // 3Wire SPI Mode }; // Initialize the MCU void InitMCU() { // Halting the Watchdog WDT_A_holdTimer(); // Enabling MASTER interrupts Interrupt_disableMaster(); // Set power state of MCU PCM_setPowerState(PCM_AM_LDO_VCORE1); // Configuring pins for peripheral/crystal usage and LED for output GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ, GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION); // Just in case the user wants to use the getACLK, getMCLK, etc. functions, // let's set the clock frequency in the code CS_setExternalClockSourceFrequency(32000,48000000); // Starting HFXT in non-bypass mode without a timeout. Before we start // we have to change VCORE to 1 to support the 48MHz frequency //PCM_setCoreVoltageLevel(PCM_VCORE1); FlashCtl_setWaitState(FLASH_BANK0, 2); FlashCtl_setWaitState(FLASH_BANK1, 2); CS_startHFXT(false); // Initializing MCLK to HFXT (effectively 48MHz) CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1); // Initializing SMCLK to HFXT (effectively 6MHz) CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_8); // Selecting pins P1.5, P1.6 and P1.7 in SPI mode GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN7 | GPIO_PIN6 | GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION); GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6); GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6); // Selecting pin 7.0 in DMAE0 GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION); // Configuring SPI in 3wire master mode for CC1200 SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig); // Enable SPI module for CC1200 SPI_enableModule(EUSCI_B0_BASE); // Configuring DMA module DMA_enableModule(); DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable); // Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0 DMA_assignChannel(DMA_CH0_EUSCIB0TX0); DMA_assignChannel(DMA_CH6_EXTERNALPIN); // Enable DMA interrupt MAP_DMA_assignInterrupt(INT_DMA_INT1, 0); MAP_DMA_disableInterrupt(INT_DMA_INT1); MAP_DMA_clearInterruptFlag(0); // Enabling MASTER interrupts Interrupt_enableMaster(); }
I have looked into the problem a lot today and I found out that this modified code now doesn't work for more then one while loop. The first time everything works fine, but then it gets buggy. As soon as I call DMA_enableInterrupt and the DMA isn't enabled, the application doesn't work.
While snooping for the problem which is probably the one from the Errata i found another thing that should be mentioned.
The function DMA_assignInterrupt assigns the interrupt and it enables it. This is not written in any documentation and the examples don't hint this.
Because of this my application didn't work till I removed assignInterrupt(luckly the default register value is what I need).
I know that the code doesn't work because the global counters are not equal.
//***************************************************************************** // // MSP432 main.c template - Empty main // //**************************************************************************** #include "driverlib.h" #include "IQmathLib.h" #pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024) static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32]; void InitMCU(); uint8_t flag; uint32_t counterMain; uint32_t counterIsr; void main(void) { InitMCU(); uint8_t buffer = 0x55; flag = 1; while(1) { if(flag) { // Clear interrupt status SPI_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT); // Activate DMA SPI transfer with external pin DMA_setChannelControl(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1); DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT, UDMA_MODE_BASIC, &buffer, (void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1); // Setup the TX transfer characteristics & buffers DMA_setChannelControl(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1); DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT, UDMA_MODE_BASIC, &buffer, (void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 3); MAP_DMA_enableChannel(0); MAP_DMA_enableChannel(6); //MAP_DMA_assignInterrupt(INT_DMA_INT1, 0); //DMA_Channel->INT1_SRCCFG = (DMA_Channel->INT1_SRCCFG & ~DMA_INT1_SRCCFG_INT_SRC_MASK) | channel; MAP_DMA_clearInterruptFlag(0); MAP_DMA_enableInterrupt(INT_DMA_INT1); // Assigning/Enabling Interrupts MAP_Interrupt_enableInterrupt(INT_DMA_INT1); flag = 0; counterMain++; GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6); } } } // DMA INT1 ISR void DMA_INT1_IRQHandler(void) { MAP_DMA_disableInterrupt(INT_DMA_INT1); MAP_Interrupt_enableInterrupt(INT_DMA_INT1); MAP_DMA_clearInterruptFlag(0); GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6); counterIsr++; flag = 1; } // SPI Master Configuration Parameter for CC1200 const eUSCI_SPI_MasterConfig spiMasterConfig = { EUSCI_B_SPI_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 6000000, // SMCLK = HFXT/8 = 6MHz 6000000, // SPICLK = 6MHz EUSCI_B_SPI_MSB_FIRST, // MSB First EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT, // Phase EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Low polarity EUSCI_B_SPI_3PIN // 3Wire SPI Mode }; // Initialize the MCU void InitMCU() { // Halting the Watchdog WDT_A_holdTimer(); // Enabling MASTER interrupts Interrupt_disableMaster(); // Set power state of MCU PCM_setPowerState(PCM_AM_LDO_VCORE1); // Configuring pins for peripheral/crystal usage and LED for output GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ, GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION); // Just in case the user wants to use the getACLK, getMCLK, etc. functions, // let's set the clock frequency in the code CS_setExternalClockSourceFrequency(32000,48000000); // Starting HFXT in non-bypass mode without a timeout. Before we start // we have to change VCORE to 1 to support the 48MHz frequency //PCM_setCoreVoltageLevel(PCM_VCORE1); FlashCtl_setWaitState(FLASH_BANK0, 2); FlashCtl_setWaitState(FLASH_BANK1, 2); CS_startHFXT(false); // Initializing MCLK to HFXT (effectively 48MHz) CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1); // Initializing SMCLK to HFXT (effectively 6MHz) CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_8); // Selecting pins P1.5, P1.6 and P1.7 in SPI mode GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN7 | GPIO_PIN6 | GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION); GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6); GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6); // Selecting pin 7.0 in DMAE0 GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION); // Configuring SPI in 3wire master mode for CC1200 SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig); // Enable SPI module for CC1200 SPI_enableModule(EUSCI_B0_BASE); // Configuring DMA module DMA_enableModule(); DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable); // Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0 DMA_assignChannel(DMA_CH0_EUSCIB0TX0); DMA_assignChannel(DMA_CH6_EXTERNALPIN); // Enable DMA interrupt //MAP_DMA_assignInterrupt(INT_DMA_INT1, 0); //MAP_DMA_enableInterrupt(INT_DMA_INT1); MAP_DMA_disableInterrupt(INT_DMA_INT1); MAP_DMA_clearInterruptFlag(0); // Enabling MASTER interrupts Interrupt_enableMaster(); }
Hi Jaselaja,
I've just run into this same set of problems.
I agree, some documentation about DMA_assignInterrupt() unexpectedly calling DMA_enableInterrupt() would be useful.
Changing the examples to at least comment this behvaiour (if not remove the redundant DMA_enableInterrupt() call) would be great.
The examples also like to call DMA_clearInterruptFlag() regardless of the DMA interrupt used, but this can cause trouble because it clears the interrupt flags for DMA_INT0 if you happen to be using it. There are no flags for DMA_INT1/2/3 so if you are using these, no need to call DMA_clearInterruptFlag().
Changing to the red Launchpad (or RevC MSP432 parts) does seem to have solved the DMA interrupt problem for me.
Cheers
Julian
**Attention** This is a public forum