嘿,社区,
有一段时间我尝试将DMA与我的I2C库集成以提高性能。 作为初始步骤,我只是想在不启用CPU的情况下将接收到的数据直接传输到内存中。因此,我配置了DMA通道4,以便它可以由我的UCB2 -I2C接收中断触发。但问题是DMA不是由该接收中断触发的。 但当我从I2C中断中提供DMAREQ时,它是有效的。我在下面附上了我的代码。 请浏览并告诉我您的建议。
注:我还在上读过Web DMA对I2C通信的贡献不及对SPI和UART的贡献。 因为我正在学习,所以我想自己学习和分析。
代码:
主要c
#include <msp430.h>
#include <i2c\I2C.h>
/**
* main.c
*/
#define ADXL_Address 0x53
#define Part_id 0x00
#define Clock_Div 80
#define Power_CTL 0x2D
#define Data_Rate 0x2C
#define Data_Format 0x31
#define X0_Reg 0x32
uint8_t adxl_Power_Ctl_cmd [TYPE_0_LENGTH] = {0x08}; //
uint8_t adxl_Data_Rate_cmd [TYPE_0_LENGTH] = {0x08}; // Lower power mode with 25 Hz bandwidth and 12.5Hz ODR ||0x17 for 6.25hz bandwith and 12.5Hz ODR
uint8_t adxl_Data_Format_cmd [TYPE_0_LENGTH] = {0x00}; //Range :+-2g INT inver bit is low
#define Power_CTL_value 0x08
#define Data_Rate_value 0x08
#define Data_Format_valu 0x00
int dma_value[10] = {0};
int data[10] = {0};
void DMA_Init()
{
DMA4CTL &=~DMAEN;
DMACTL1 |= DMA4TSEL__UCB2RXIFG0;
// DMACTL4 &=~DMARMWDIS;
DMACTL4 |=DMARMWDIS;
DMA4CTL &=~DMA4CTL;
__data20_write_long((uintptr_t) &DMA4SA,(uintptr_t) &UCB2RXBUF);
__data20_write_long((uintptr_t) &DMA4DA,(uintptr_t) &dma_value);
DMA4SZ = 6;
DMA4CTL |=DMADT_4|DMADSTINCR_3|DMASRCINCR_0|DMASRCBYTE__WORD|DMADSTBYTE__WORD|DMALEVEL__EDGE|DMAEN;
}
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
DMA_Init();
initGPIO();
initI2C(ADXL_Address, Clock_Div);
while(1)
{
// I2C_Master_ReadReg(ADXL_Address, Part_id, TYPE_0_LENGTH);
I2C_Master_WriteReg(ADXL_Address, Data_Rate, adxl_Data_Rate_cmd, TYPE_0_LENGTH);
I2C_Master_WriteReg(ADXL_Address, Data_Format, adxl_Data_Format_cmd, TYPE_0_LENGTH);
I2C_Master_WriteReg(ADXL_Address, Power_CTL, adxl_Power_Ctl_cmd, TYPE_0_LENGTH);
I2C_Master_ReadReg(ADXL_Address, X0_Reg, TYPE_2_LENGTH);
data[0] = (short)((((unsigned short)dma_value[1]) << 8) | dma_value[0]);
data[1] = (short)((((unsigned short)dma_value[3]) << 8) | dma_value[2]);
data[2] = (short)((((unsigned short)dma_value[5]) << 8) | dma_value[4]);
__delay_cycles(1000000);
}
return 0;
}
I2C.h
/*
* I2C.h
*
* Created on: 10-Feb-2022
* Author: TOSHIBA
*/
#ifndef I2C_I2C_H_
#define I2C_I2C_H_
/*
* i2c.h
*
* Created on: 09-Oct-2021
* Author: TOSHIBA
*/
#ifndef I2C_H_
#define I2C_H_
#include <msp430.h>
#include <stdint.h>
#include <stdbool.h>
//******************************************************************************
// Pin Config ******************************************************************
//******************************************************************************
#define LED_OUT P1OUT
#define LED_DIR P1DIR
#define LED0_PIN BIT0
#define LED1_PIN BIT1
#define CMD_TYPE_0_SLAVE 0x00
#define CMD_TYPE_1_SLAVE 0x1D
#define CMD_TYPE_2_SLAVE 3
#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 20
/* MasterTypeX are example buffers initialized in the master, they will be
* sent by the master to the slave.
* SlaveTypeX are example buffers initialized in the slave, they will be
* sent by the slave to the master.
* */
//uint8_t MasterType2 [TYPE_2_LENGTH] = {'F', '4', '1', '9', '2', 'B'};
//uint8_t MasterType1 [TYPE_1_LENGTH] = { 8, 9};
//uint8_t MasterType0 [TYPE_0_LENGTH] = {0x08};
//uint8_t MasterType3 [TYPE_0_LENGTH] = {0x0A};
//uint8_t MasterType4 [TYPE_0_LENGTH] = {0x03};
//
//
uint8_t SlaveType2 [TYPE_2_LENGTH] = {0};
uint8_t SlaveType1 [TYPE_1_LENGTH] = {0};
uint8_t SlaveType0 [TYPE_0_LENGTH] = {0};
//
//
//uint8_t Power_CTL_value [TYPE_0_LENGTH] = {0x08};
//uint8_t Data_Rate_value [TYPE_0_LENGTH] = {0x0A};
//uint8_t Data_Format_value [TYPE_0_LENGTH] = {0x03};
typedef enum I2C_ModeEnum{
IDLE_MODE,
NACK_MODE,
TX_REG_ADDRESS_MODE,
RX_REG_ADDRESS_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
SWITCH_TO_RX_MODE,
SWITHC_TO_TX_MODE,
TIMEOUT_MODE
} I2C_Mode;
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
void initGPIO();
void initClockTo16MHz();
void initI2C(uint8_t SLAVE_ADDR,uint8_t clk_div);
/* Used to track the state of the software state machine*/
I2C_Mode MasterMode = IDLE_MODE;
/* The Register Address/Command to use*/
uint8_t TransmitRegAddr = 0;
/* ReceiveBuffer: Buffer used to receive data in the ISR
* RXByteCtr: Number of bytes left to receive
* ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
* TransmitBuffer: Buffer used to transmit data in the ISR
* TXByteCtr: Number of bytes left to transfer
* TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
* */
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
{
/* Initialize state machine */
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
RXByteCtr = count;
TXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
/* Initialize slave address and interrupts */
UCB2I2CSA = dev_addr;
UCB2IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts
UCB2IE &= ~UCRXIE; // Disable RX interrupt
UCB2IE |= UCTXIE; // Enable TX interrupt
UCB2CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
__enable_interrupt();
__bis_SR_register(LPM0_bits); // Enter LPM0 w/ interrupts
return MasterMode;
}
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
/* Initialize state machine */
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
//Copy register data to TransmitBuffer
CopyArray(reg_data, TransmitBuffer, count);
TXByteCtr = count;
RXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
/* Initialize slave address and interrupts */
UCB2I2CSA = dev_addr;
UCB2IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts
UCB2IE &= ~UCRXIE; // Disable RX interrupt
UCB2IE |= UCTXIE; // Enable TX interrupt
UCB2CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
__enable_interrupt();
__bis_SR_register(LPM0_bits); // Enter LPM0 w/ interrupts
return MasterMode;
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************
void initGPIO()
{
// Configure GPIO
LED_OUT &= ~(LED0_PIN | LED1_PIN); // P1 setup for LED & reset output
LED_DIR |= (LED0_PIN | LED1_PIN);
// I2C pins
P7SEL0 |= BIT0 | BIT1;
P7SEL1 &= ~(BIT0 | BIT1);
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
}
void initClockTo16MHz()
{
// Configure one FRAM waitstate as required by the device datasheet for MCLK
// operation beyond 8MHz _before_ configuring the clock system.
FRCTL0 = FRCTLPW | NWAITS_1;
// Clock System Setup
CSCTL0_H = CSKEY_H; // Unlock CS registers
CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
// Set SMCLK = MCLK = DCO, ACLK = LFXTCLK (VLOCLK if unavailable)
CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;
// Per Device Errata set divider to 4 before changing frequency to
// prevent out of spec operation from overshoot transient
CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata
CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz
// Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
__delay_cycles(60);
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers to 1 for 16MHz operation
CSCTL0_H = 0; // Lock CS registers
}
void initI2C(uint8_t SLAVE_ADDR,uint8_t clk_div)
{
UCB2CTLW0 = UCSWRST; // Enable SW reset
UCB2CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
UCB2BRW = 10; // fSCL = SMCLK/160 = ~100kHz
UCB2I2CSA = SLAVE_ADDR; // Slave Address
UCB2CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation
UCB2IE |= UCNACKIE;
}
#endif /* I2C_H_ */
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B2_VECTOR
__interrupt void USCI_B2_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B2_VECTOR))) USCI_B2_ISR (void)
#else
#error Compiler not supported!
#endif
{
//Must read from UCB2RXBUF
uint8_t rx_val = 0;
switch(__even_in_range(UCB2IV, USCI_I2C_UCBIT9IFG))
{
case USCI_NONE: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
break;
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3
case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2
case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2
case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1
case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1
case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0
// rx_val = UCB2RXBUF;
DMA4CTL |=DMAREQ;
if (RXByteCtr)
{
// ReceiveBuffer[ReceiveIndex++] = rx_val;
RXByteCtr--;
}
if (RXByteCtr == 1)
{
UCB2CTLW0 |= UCTXSTP;
}
else if (RXByteCtr == 0)
{
UCB2IE &= ~UCRXIE;
MasterMode = IDLE_MODE;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0
switch (MasterMode)
{
case TX_REG_ADDRESS_MODE:
UCB2TXBUF = TransmitRegAddr;
if (RXByteCtr)
MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now
else
MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer
break;
case SWITCH_TO_RX_MODE:
UCB2IE |= UCRXIE; // Enable RX interrupt
UCB2IE &= ~UCTXIE; // Disable TX interrupt
UCB2CTLW0 &= ~UCTR; // Switch to receiver
MasterMode = RX_DATA_MODE; // State state is to receive data
UCB2CTLW0 |= UCTXSTT; // Send repeated start
if (RXByteCtr == 1)
{
//Must send stop since this is the N-1 byte
while((UCB2CTLW0 & UCTXSTT));
UCB2CTLW0 |= UCTXSTP; // Send stop condition
}
break;
case TX_DATA_MODE:
if (TXByteCtr)
{
UCB2TXBUF = TransmitBuffer[TransmitIndex++];
TXByteCtr--;
}
else
{
//Done with transmission
UCB2CTLW0 |= UCTXSTP; // Send stop condition
MasterMode = IDLE_MODE;
UCB2IE &= ~UCTXIE; // disable TX interrupt
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
default:
__no_operation();
break;
}
break;
default: break;
}
}
#endif /* I2C_I2C_H_ */