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.

How to configure sd24_b DMA transfer?

I've successfully integrated the sd24_b driver (24-bit sigma delta ADC) and am starting to use the DMA controller, using code from the TI-provided driver library.  I've run the DMA repeated Block example as a unit test and it works.  However, I can't seem to get an ADC conversion to trigger a DMA transfer.  I've included a version of my code below that should compile and run with the TI library.  Even when using a dummy source buffer address, I don't see any data transferred to the destination buffer, so perhaps the interrupts aren't setup correctly?


Quesitons:

1) How should I set the "source address" for the DMA?  The ADC12 driver has a "GetMemoryAddress" function and that address is passed into the DMA driver.  I think I should just give DMA the address of SD24's 'OFS_SD24BMEML0' output register and transfer 4 bytes at a time.

2) What's wrong with the interrupt/DMA setup such that a transfer is not being triggered?

===========================================

#define ADC24SD_BASE_ADDRESS    (TUSIGN16)__MSP430_BASEADDRESS_SD24_B__
#define DMA_BASE_ADDRESS        (TUSIGN16)__MSP430_BASEADDRESS_DMAX_3__
#define MIN_CYCLES_FOR_ADC_MEASUREMENT  1000u
#define TEST_BUFFER_SIZE 25u
static TUSIGN32 testDestinationBuffer[TEST_BUFFER_SIZE] = {0};

// 'Unity' unit test wrapper. TEST(ADCSigmaDelta24Bit, ConfigureDMATrigger_TriggerASingleDMATransfer) { // Setup the ADC. SD24_B_initializeParam adcInitialiseParams = (SD24_B_initializeParam){.clockSourceSelect = SD24_B_CLOCKSOURCE_MCLK, .clockPreDivider = SD24_B_PRECLOCKDIVIDER_1, .clockDivider = SD24_B_CLOCKDIVIDER_1, .referenceSelect = SD24_B_REF_INTERNAL}; SD24_B_initialize(ADC24SD_BASE_ADDRESS, &adcInitialiseParams); const TUSIGN8 TEST_CONVERTER = SD24_B_CONVERTER_1; SD24_B_initConverterParam adcInitConverterParams = (SD24_B_initConverterParam){.converter = TEST_CONVERTER, .alignment = SD24_B_ALIGN_RIGHT, .startSelect = SD24_B_CONVERSION_SELECT_SD24SC, .conversionMode = SD24_B_SINGLE_MODE}; InitConverter_ADCSigmaDelta24Bit(ADC24SD_BASE_ADDRESS, &adcInitConverterParams); SD24_B_configureDMATrigger(ADC24SD_BASE_ADDRESS, SD24_B_DMA_TRIGGER_IFG1); // Do NOT enable interrupts or else only the ISR will see the interrupt flag, not the DMA. DisableInterrupt_ADCSigmaDelta24Bit(ADC24SD_BASE_ADDRESS, TEST_CONVERTER, SD24_B_CONVERTER_INTERRUPT); ClearInterrupt_ADCSigmaDelta24Bit(ADC24SD_BASE_ADDRESS, TEST_CONVERTER, SD24_B_CONVERTER_INTERRUPT); // Setup the DMA. const TUSIGN8 TEST_DMA_CHANNEL = DMA_CHANNEL_0; // doesn't matter which channel. const TUSIGN8 TEST_TRANSFER_SIZE = sizeof(TUSIGN32) / sizeof(TUSIGN); DMA_initializeParam dmaInitialiseParams = (DMA_initializeParam){.channelSelect = TEST_DMA_CHANNEL, .transferModeSelect = DMA_TRANSFER_BLOCK, .transferSize = TEST_TRANSFER_SIZE, .triggerSourceSelect = DMA_TRIGGER_SOURCE_SD24IFG, .transferUnitSelect = DMA_SIZE_SRCWORD_DSTWORD, .triggerTypeSelect = DMA_TRIGGER_RISINGEDGE}; DMA_initialize(&dmaInitialiseParams); // Calculate address to ADC24SD low word TUSIGN16 adc24SDAddress = ADC24SD_BASE_ADDRESS + (TUSIGN16)(OFS_SD24BMEML0 + (TEST_CONVERTER << 2u)); SetSourceAddress_DMA(TEST_DMA_CHANNEL, (TUSIGN32)adc24SDAddress, DMA_DIRECTION_UNCHANGED); // TUSIGN16 testSrcBuffer[TEST_BUFFER_SIZE] = {0xAAAA, 0x5555, 0xDDDD, 0x2222, 0x1111, 0xCCCC}; // SetSourceAddress_DMA(TEST_DMA_CHANNEL, (TUSIGN32)testSrcBuffer, DMA_DIRECTION_UNCHANGED); SetDestinationAddress_DMA(TEST_DMA_CHANNEL, (TUSIGN32)testDestinationBuffer, DMA_DIRECTION_INCREMENT); ClearInterrupt_DMA(TEST_DMA_CHANNEL); EnableInterrupt_DMA(TEST_DMA_CHANNEL); EnableTransfers_DMA(TEST_DMA_CHANNEL); // Start the ADC conversion, which will trigger the DMA transfer once it finishes. SD24_B_startConverterConversion(ADC24SD_BASE_ADDRESS, TEST_CONVERTER); __delay_cycles(MIN_CYCLES_FOR_ADC_MEASUREMENT); // Verify that the single ADC result was automatically transferred to the buffer by the DMA. TUSIGN32 result = SD24_B_getResults(ADC24SD_BASE_ADDRESS, TEST_CONVERTER); TEST_ASSERT_EQUAL(testDestinationBuffer[0], result); }

=============================================================

  • I've now discovered that the issue with receiving SD24B interrupts for the DMA was due to a bug in the TI driver library file "sd24_b.c", in the function "SD24_B_configureDMATrigger".  Instead of

    HWREG16(baseAddress + OFS_SD24BCTL1) &= ~(SD24DMA_3 | SD24DMA_2 | SD24DMA_1 | SD24DMA_0);
    HWREG16(baseAddress + OFS_SD24BCTL1) |= interruptFlag;

    it should read

    HWREG16(baseAddress + OFS_SD24BCTL1) &= ~(SD24DMA3 | SD24DMA2 | SD24DMA1 | SD24DMA0);
    HWREG16(baseAddress + OFS_SD24BCTL1) |= interruptFlag;

    The difference is that "SD24DMA_3" refers to the number 3, whereas SD24DMA3 refers to the third bit (see msp430xgeneric.h lines 8789 and 8804).  Therefore the original code was clearing only two bits out of four, whereas the corrected code clears all four bits.  The rest of the code is correct.  And be careful that you can only change the source and destination addresses while DMA transfers are disabled.


    Note that the HW is not setup for the DMA to copy X samples of 32-bits from the ADC before firing an interrupt, but Robert Cowsill proposes some solutions in this post:   http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/403683

**Attention** This is a public forum