Hello,
I am trying to send data over I2C via DMA in a loop. MSP432 board is in master mode and aardwark dongle is configured in slave mode.
I have modified the example dma_eusci_i2c_loopback to send data of 1024 bytes in a for loop. In the first loop, all 1024 bytes is sent successfully. On the subsequent tries, sometimes 5 or 6 bytes are sent (with the first byte missing). If I change the speed to 400kbpsm, sometimes, the dma isr doesnt get called. Always the first transfer is a success.
I have attached my code here. Appreciate the help. Thanks.
/*
* -------------------------------------------
* MSP432 DriverLib - v2_20_00_08
* -------------------------------------------
*
* --COPYRIGHT--,BSD,BSD
* Copyright (c) 2014, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
/*******************************************************************************
* MSP432 DMA - eUSCI I2C Transfer Using DMA
*
* Description: In this code example, the MSP432 's DMA controller is used in
* conjunction with an I2C loopback configuration to demonstrate how to use
* hardware triggered DMA transfers. Two DMA transfers are setup using two
* different channels. Channel 2 is used for the DMA transfer and Channel 5 is
* used for the DMA receive. Once the transfers are setup and initialized, the
* device is put to sleep. While sleeping, the DMA controller will automatically
* transfer the data from the const array and out through the uESCI B1 I2C
* module as a master. The slave, which is setup on eUSCI B2, will automatically
* trigger the DMA controller to place the incoming data in a RAM buffer called
* recBuffer. When the DMA transfer is complete, an interrupt will be fired and
* the master will send a stop condition out over the I2C Line.
*
* This program runs infinitely until manually halted by the user.
*
* MSP432P401
* ------------------
* /|\| | <10k Pull-Up>
* | | | | |
* --|RST P6.5 (SDA) |---|---------
* | P6.4 (SCL) |---------- |
* | | | |
* | P3.6 (SCL) |---------- |
* | P3.7 (SCL) |-------------
* | |
*
* Author: Timothy Logan
******************************************************************************/
/* DriverLib Includes */
#include "driverlib.h"
/* Standard Includes */
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
/* Statics */
static uint8_t recBuffer[1024];
static volatile bool sendStopCondition;
/* I2C Configuration Parameter */
const eUSCI_I2C_MasterConfig i2cMasterConf =
{
EUSCI_B_I2C_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
3000000, // SMCLK = 3MHz
EUSCI_B_I2C_SET_DATA_RATE_100KBPS, // Desired I2C Clock of 100khz
0, // No Auto Stop
EUSCI_B_I2C_NO_AUTO_STOP // No Auto Stop
};
/* DMA Control Table */
#ifdef ewarm
#pragma data_alignment=256
#else
#pragma DATA_ALIGN(controlTable, 256)
#endif
uint8_t controlTable[256];
/* Extern */
extern uint8_t data_array[];
void read_from_slave(unsigned char addr, void *destAddress, int transferSize);
void send_to_slave(unsigned char addr, void *srcAddress, int transferSize);
// dma to aardwark works using this B0 module only.
#define EUSCI_BX_MODULE EUSCI_B0_MODULE
#define DMA_CHX_EUSCIBXTX DMA_CH0_EUSCIB0TX0
#define DMA_CHX_EUSCIBXRX DMA_CH1_EUSCIB0RX0
#define DMA_CHANNEL_TX 0
#define DMA_CHANNEL_RX 1
#define DMA_INTTX DMA_INT1
#define DMA_INTRX DMA_INT2
void loop(void) {
while(1)
{
if(sendStopCondition)
{
break;
}
MAP_PCM_gotoLPM0InterruptSafe();
}
}
int main(void)
{
/* Halting Watchdog */
MAP_WDT_A_holdTimer();
/* Initializing I2C Master on EUSCIB1 at 400Khz */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
MAP_I2C_initMaster(EUSCI_BX_MODULE, &i2cMasterConf);
MAP_I2C_enableModule(EUSCI_BX_MODULE);
/* Configuring DMA module */
MAP_DMA_enableModule();
MAP_DMA_setControlBase(controlTable);
/* Assigning Channel 0 and 1 */
MAP_DMA_assignChannel(DMA_CHX_EUSCIBXTX);
MAP_DMA_assignChannel(DMA_CHX_EUSCIBXRX);
/* Disabling channel attributes */
MAP_DMA_disableChannelAttribute(DMA_CHX_EUSCIBXTX,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
MAP_DMA_disableChannelAttribute(DMA_CHX_EUSCIBXRX,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
/* Setting Control Indexes */
MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CHX_EUSCIBXTX,
UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CHX_EUSCIBXRX,
UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
/* Assigning/Enabling Interrupts */
MAP_DMA_assignInterrupt(DMA_INTTX, DMA_CHANNEL_TX);
MAP_DMA_assignInterrupt(DMA_INTRX, DMA_CHANNEL_RX);
// enable interrupts
MAP_Interrupt_enableInterrupt(DMA_INTTX);
MAP_Interrupt_enableInterrupt(DMA_INTRX);
/* Enabling master interrupts */
MAP_Interrupt_enableMaster();
int i, j;
for (i = 0; i < 5; i ++) {
sendStopCondition = false;
MAP_Interrupt_enableSleepOnIsrExit();
send_to_slave(0x48, data_array, 1024);
loop ();
// sleep
for(j = 0; j < 100000; j ++);
}
sendStopCondition = false;
}
void send_to_slave(unsigned char addr, void *srcAddress, int transferSize)
{
// set slave address
MAP_I2C_setSlaveAddress(EUSCI_BX_MODULE, addr);
// set in transmit mode
MAP_I2C_setMode(EUSCI_BX_MODULE, EUSCI_B_I2C_TRANSMIT_MODE);
// tx channel
MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CHX_EUSCIBXTX,
UDMA_MODE_BASIC, srcAddress,
(void*) MAP_I2C_getTransmitBufferAddressForDMA(EUSCI_BX_MODULE), transferSize);
MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CHX_EUSCIBXTX,
UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
/* Clear flag */
MAP_DMA_clearInterruptFlag(DMA_CHANNEL_TX);
/* enable interrupt */
MAP_DMA_enableInterrupt(DMA_INTTX);
MAP_Interrupt_enableInterrupt(DMA_INTTX);
/* Now that the DMA is primed and setup, enabling the channels. The EUSCI
* hardware should take over and transfer/receive all bytes */
MAP_DMA_enableChannel(DMA_CHANNEL_TX);
/* Sending the start condition */
MAP_I2C_masterSendStart(EUSCI_BX_MODULE);
while(!MAP_I2C_masterIsStartSent(EUSCI_BX_MODULE));
}
void read_from_slave(unsigned char addr, void *destAddress, int transferSize)
{
// set slave address
MAP_I2C_setSlaveAddress(EUSCI_BX_MODULE, addr);
/* Set in receive mode */
MAP_I2C_setMode(EUSCI_BX_MODULE, EUSCI_B_I2C_RECEIVE_MODE);
// rx channel
MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CHX_EUSCIBXRX,
UDMA_MODE_BASIC, (void*)MAP_I2C_getReceiveBufferAddressForDMA(EUSCI_BX_MODULE),
destAddress, transferSize);
/* Clear flag */
MAP_DMA_clearInterruptFlag(DMA_CHANNEL_RX);
/* enable interrupt */
MAP_DMA_enableInterrupt(DMA_INTRX);
MAP_Interrupt_enableInterrupt(DMA_INTRX);
/* Now that the DMA is primed and setup, enabling the channels. The EUSCI
* hardware should take over and transfer/receive all bytes */
MAP_DMA_enableChannel(DMA_CHANNEL_RX);
// Sending the receive
MAP_I2C_masterReceiveStart(EUSCI_BX_MODULE);
}
static int euscib1_isr_count = 0;
void euscib1_isr(void)
{
euscib1_isr_count ++;
}
static int euscib2_isr_count = 0;
void euscib2_isr(void)
{
euscib2_isr_count ++;
}
/* Completion interrupt for eUSCIB1 RX */
void dma_2_interrupt(void)
{
/* Clear flag */
MAP_DMA_clearInterruptFlag(DMA_CHANNEL_RX);
/* Disabling the completion interrupt and disabling the DMA channels */
MAP_DMA_disableChannel(DMA_CHANNEL_RX);
MAP_DMA_disableInterrupt(DMA_INTRX);
MAP_I2C_masterReceiveMultiByteStop(EUSCI_BX_MODULE);
}
/* Completion interrupt for eUSCIB1 TX */
void dma_1_interrupt(void)
{
/* Clear flag */
MAP_DMA_clearInterruptFlag(DMA_CHANNEL_TX);
/* Disabling the completion interrupt and disabling the DMA channels */
MAP_DMA_disableChannel(DMA_CHANNEL_TX);
MAP_DMA_disableInterrupt(DMA_INTTX);
MAP_I2C_masterSendMultiByteStop(EUSCI_BX_MODULE);
while(!MAP_I2C_masterIsStopSent(EUSCI_BX_MODULE));
sendStopCondition = true;
// MAP_I2C_disableModule(EUSCI_BX_MODULE);
}