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.

MSP432P401R: ADC Values and Memory

Part Number: MSP432P401R

I am beginning a project where I am using the MSP432 as a sequencer in an electronic drum machine. I have already written code that successfully samples the output of a few drum circuits, via ADC, and I have a few audio samples that I would also like to integrate into the project. Currently, I am having a few issues that I would love some guidance on.

  1. Where should I save the values (from the drum circuit) recorded by the ADC?
  2. How/Where do I save audio samples in the MSP432 for combination with the digital voltages that I have determined via ADC?

Thank you for any assistance that anybody can provide!

  • The adc14_single_conversion_repeat_timera_source example is probably the closest to what you are trying to do. This example simply creates a buffer to store ADC samples to memory at a regular interval using the timerA module. This particular example doesn't have a TimerA ISR, but you could enable that interrupt and create one to sample the digital IO and the same interval as the ADC samples (or some multiple thereof) if that's desirable.

    -Bob L.

  • Thank you for your help Bob! I've done some research and I think what I want to do is store the ADC results in RAM, so that they will be erased when the MSP432 is powered down. However, I can't seem to find any resources pointing out how this might be done. Any suggestions?
  • The example that Bob mentioned shows one method of storing ADC data in an array.

    If you're not using driverlib, example (SLAC698D) adc14_06 provides an example as well. (It uses a different mode in the ADC, so just ignore that part.)
  • Hello Nyssa,

    you can store your drum samples in FRAM.
    Probably the easiest way to do it is using #pragma directive:

    #include <ti/drivers/NVS.h>
    #include <ti/drivers/nvs/NVSSPI25X.h>
    #include <ti/drivers/nvs/NVSCC26XX.h>

    #define NVS_REGIONS_BASE 0x1A000
    #define SECTORSIZE 0x1000
    #define REGIONSIZE (SECTORSIZE * 4)
    #define SPIREGIONSIZE (SECTORSIZE * 32)
    #define VERIFYBUFSIZE 64

    static uint8_t verifyBuf[VERIFYBUFSIZE];

    /*
    * Reserve flash sectors for NVS driver use by placing an uninitialized byte
    * array at the desired flash address.
    */
    #if defined(__TI_COMPILER_VERSION__)

    /*
    * Place uninitialized array at NVS_REGIONS_BASE
    */

    #pragma LOCATION(flashBuf, NVS_REGIONS_BASE);

    #pragma NOINIT(flashBuf);
    static char flashBuf[REGIONSIZE];

    #elif defined(__IAR_SYSTEMS_ICC__)

    /*
    * Place uninitialized array at NVS_REGIONS_BASE
    */
    static __no_init char flashBuf[REGIONSIZE] @ NVS_REGIONS_BASE;

    #elif defined(__GNUC__)

    /*
    * Place the flash buffers in the .nvs section created in the gcc linker file.
    * The .nvs section enforces alignment on a sector boundary but may
    * be placed anywhere in flash memory. If desired the .nvs section can be set
    * to a fixed address by changing the following in the gcc linker file:
    *
    * .nvs (FIXED_FLASH_ADDR) (NOLOAD) : AT (FIXED_FLASH_ADDR) {
    * *(.nvs)
    * } > REGION_TEXT
    */
    __attribute__ ((section (".nvs")))
    static char flashBuf[REGIONSIZE];

    #endif

    I hope the above example would help you.
    It is so huge because you have not mentioned compiler version you are using.
    Keep on mind that some pragmas have different syntax in C and C++.

  • Thank you very much! I'm going to try this now, and I'm using Code Composer Studio 7.1.0.
  • I looked over the example that you suggested and attempted to implement a similar fix yet, when I watch the register values in the debugger I only notice ADC14MEM0 and ADC14MEM2 changing.

    The following is my ADC ISR, where I am trying to store the resulting values in different locations based on the pin that triggered the interrupt driving the ADC.

    void ADC14_IRQHandler(void) {
      
        if((P3->IFG)&& BIT0){
           SDresults[index] = ADC14->MEM[0];   // Move results, IFG is cleared
        }
        if((P3->IFG) && BIT2){
           WBresults[index] = ADC14->MEM[1];
        }
        if((P3->IFG) && BIT3){
           LTresults[index] = ADC14->MEM[2];
        }
        if((P3->IFG) && BIT5){
           HTresults[index] = ADC14->MEM[3];
        }
        if((P3->IFG) && BIT6){
           BDresults[index] = ADC14->MEM[4];
        }
        index = (index + 1) & 0x0F;          // Increment results index, modulo
        __no_operation();                   // Set Breakpoint1 here
    }

    Additionally, this is the code where I initialize everything used above.

    #define   Num_of_Results   16
    volatile uint16_t SDresults[Num_of_Results];
    volatile uint16_t WBresults[Num_of_Results];
    volatile uint16_t LTresults[Num_of_Results];
    volatile uint16_t HTresults[Num_of_Results];
    volatile uint16_t BDresults[Num_of_Results];
    static uint8_t index;

  • > if((P3->IFG)&& BIT0){
    This doesn't do what you want. It should be more like:
    > if((P3->IFG)& BIT0){
    ------
    Except that that isn't what you want either: In order to get out of the port3 ISR, you need to set P3->IFG=0 (for at least the relevant bits), so by the time you get here P3->IFG is (almost) certainly 0.

    You probably want to save a copy of P3->IFG ("saved_IFG = P3->IFG;") before you clear it in the port3 ISR, and refer to that when you're fetching the ADC results.
  • Nyssa,

    good that you have mentioned you are using CC v7.1.
    I had a short discussion with a good TI guy and he told me that he is using 5 different CSS versions.
    The key for a success is to use different workspaces for different CCS's.

    Bruce,
    could you help Nyssa and me how to deal with different version of CCS's?
    It is important for all of us to flexibly move between CCS versions and its tools chains.
    An example: I have CCS v7.4 and I cannot install the newest XDStools.

    Sooner or later a transition to 64-bit is a must.


    Thanks!

  • > how to deal with different version of CCS's?
    This is a bit off topic, but:

    I also have multiple versions of CCS, and I keep separate workspaces and separate installation directories. When I install an upgrade, I use it (somewhat lazily) to import/check my older workspace and only then uninstall the previous version. This is mostly superstition at this point -- I haven't encountered an upgrade problem in many years, so I haven't had occasion to go backwards.

    It sounds as though Nyssa Backes is doing just fine with 7.1.0, though I expect it would be no problem to upgrade.

    It sounds as though you (or XDSTools) need some feature which is only in a newer version, so you need to upgrade.
  • Thank you again! I've saved a copy of P3->IFG before it gets cleared in the Port 3 ISR and then I use the value in the ADC ISR to determine where the resultant values should be stored. Yet, when I check the values stored for each of the interrupts only the P3.0 interrupts stores accurate values that change for differing input. The other interrupts result in an array of the same value being stored for each input.

    For example, the P3.2 interrupt always stores WBresults unsigned short[16] [64,64,64,64,64...] for every input, while the P3.3 interrupt saves LTresults unsigned short[16] [1024,1024,1024,1024,1024...] for every input voltage on the ADC pin.

    Thank you again for any assistance that you can provide.

    This is the Port 3 ISR.

    void PORT3_IRQHandler(void)       //Interrupt handler for Port 3
    {
           saved_IFG = P3->IFG;
           button_flag = 1;              //Set flag to signal button press detected
           //configure Timer A0
           TA0CCR0 = 900000;             //Timer length = 300ms
           TA0CCTL0 |= CCIE;
           TA0CTL |= TASSEL_2 | MC_1;
           saved_IFG = P3->IFG;
           P3->IFG = 0;                  //Clear P3.0 pending interrupt flag
           P3->IE  &= ~BIT0;            //Disable interrupt for P3.0 for debouncing
           P3->IE  &= ~BIT2;             //Disable interrupt for P3.0 for debouncing
    }



    This is the ADC ISR.
    void ADC14_IRQHandler(void) {   // ADC14 interrupt service routine
    
        if(saved_IFG & BIT0){
           SDresults[index] = ADC14->MEM[0];   // Move results, IFG is cleared
        }else if(saved_IFG & BIT2){
           WBresults[index] = ADC14->MEM[1];
        }else if(saved_IFG & BIT3){
           LTresults[index] = ADC14->MEM[2];
        }else if(saved_IFG & BIT5){
           HTresults[index] = ADC14->MEM[3];
        }else if(saved_IFG & BIT6){
           BDresults[index] = ADC14->MEM[4];
        }
        index = (index + 1) & 0x0F;          // Increment results index
    }

    This is how I initialize everything used above.

    //new stuff
    #define   Num_of_Results   16
    volatile uint16_t SDresults[Num_of_Results];
    volatile uint16_t WBresults[Num_of_Results];
    volatile uint16_t LTresults[Num_of_Results];
    volatile uint16_t HTresults[Num_of_Results];
    volatile uint16_t BDresults[Num_of_Results];
    static uint8_t index;
    volatile int saved_IFG;

  • The last code I saw only sampled one channel (into MEM[0]). How are you setting up the other channels? (Keep in mind that you can't change INCH when ENC=1.)
  • Thank you very much! I realized my mistake was trying to save results from MEM[1], MEM[2], etc. when I really only needed to use MEM[0]. Thank you again for all of your help!

**Attention** This is a public forum