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.

Wireless Measurement System

Other Parts Discussed in Thread: MSP430FR5739

Hello

I am using the MSP430FR5739+CC3000 Evaluation Kit. I am attempting to use this kit as a measurement device capable of 100 kSamples/Second. I have adapted the "Basic Wifi App" code, so that I can send an array on request. I am now left with sampling and packaging the data that I need. I dont need low power states because my main aim is to have a high sample rate, and data transfer on the Wifi network.

What I would like to do is have the DMA build up a buffer while the Send Function reads from another buffer. After this I would like to swap the buffers and repeat the process. My problem now comes in with the size of the buffers. The CC3000 device is capable of sending 1468 Bytes (http://processors.wiki.ti.com/index.php/CC3000_Release_Notes). I would like to create a sending buffer with about 1250 Bytes so that the overhead of the TCP packet will have less effect on the effective sampling rate. The problem with this is that the FR5739 device only has 16 kBytes of memory.  I cannot declare two arrays of 1250 values, because the systems "RAM" cannot deal with variables of this size.

Is it possible to adjust the memory map of the device so that I can create two secure buffers?

The DMA example code (from CCS5) will assign a memory address within the program code, and then effectively use pointer notation to iterate through the program/data memory. However I dont know how I could choose a memory location to use, because I am sure that if I iterate through 1250 (or effectively 2500) memory addresses I will eventually overwrite some program code.

Does anyone have a suggestion on how I can create two secure memory locations (buffers) for this project?

Many Thanks

Carson

  • Hi Carson,

    If I understand correctly you would like to use the FRAM as RAM.  If so, then yes you can modify the Linker to preserve some FRAM for data usage.  Look at the CC3000 DataLogger Application.   It uses around 1500 bytes of FRAM to data log to and then sends this buffer via the CC3000.

  • Hi Carson, 

    As suggested already, increase the space of the FRAM_DATA

    In CCS, look at the linker command file (lnk_msp430fr5739.cmd) and increase the size of the FRAM_DATA and adjuxt the FRAM origin

    FRAM_DATA : origin = 0xC200, length = 0x0BE0
    FRAM : origin = 0xCDE0, length = 0x31A0

    In the code use the pragma directive: 

    #ifdef __CCS__
    #pragma DATA_SECTION(spi_buffer, ".FRAM_DATA")
    char spi_buffer[CC3000_RX_BUFFER_SIZE];

    #elif __IAR_SYSTEMS_ICC__
    #pragma location = "FRAM_DATA"
    __no_init char spi_buffer[CC3000_RX_BUFFER_SIZE];
    #endif

    Pedro

  • Thank you both for the advice!

    I reviewed the Data Logger demo code, and modified the linker command file. I created 3 big buffers, and and am addressing them directly with pointers.

    Solution found!

    Thanks again.

    Carson

  • Hello again

    On further inspection, I have found more problems. I modified the linker command file to create 3 big buffers:


        SFR                     : origin = 0x0000, length = 0x0010
        PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
        PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100

        RAM                     : origin = 0x1C00, length = 0x0400

        INFOA                   : origin = 0x1880, length = 0x0080
        INFOB                   : origin = 0x1800, length = 0x0080
    // Original:
    //    FRAM_DATA                : origin = 0xC200, length = 0x00F0
    //    FRAM                    : origin = 0xC2F0, length = 0x3C90  //was   : origin = 0xC200, length = 0x3D80

    // Modified Memory Map
        FRAM                                                : origin = 0xC200, length = 0x2780
        FRAM_DATA_SEND_BUFFER   : origin = 0xE980, length = 0x0800
        FRAM_DATA_ADC_BUFFER0   : origin = 0xF180, length = 0x0700
        FRAM_DATA_ADC_BUFFER1   : origin = 0xF880, length = 0x0700

    ...

     .bss       : {} > RAM                /* GLOBAL & STATIC VARS              */
        .stack     : {} > RAM (HIGH)         /* SOFTWARE SYSTEM STACK             */

        .FRAM_DATA_SEND_BUFFER : {} > FRAM_DATA_SEND_BUFFER
        //.fram_log1  : {} > FRAM_DATA_LOG1
        .fram_adc_buf0  : {} > FRAM_DATA_ADC_BUFFER0
        .fram_adc_buf1  : {} > FRAM_DATA_ADC_BUFFER1
        .infoA     : {} > INFOA              /* MSP430 INFO FRAM  MEMORY SEGMENTS */
        .infoB     : {} > INFOB

        .int00   : {} > INT00                /* MSP430 INTERRUPT VECTORS          */
        .int01   : {} > INT01
        .int02   : {} > INT02

    ...

    There were no compiler issues with this modified memory map. My next aim was to setup two DMA channels.  I am trying to fill one buffer while the other is being sent. However there is an issue with the memory positions being assigned to DMA1. This is my setup:

      //****************************************************************************************************************************************
      // Configure DMA (ADC10IFG trigger)

       DMACTL0 = DMA0TSEL__ADC10IFG;                                                                                       // ADC10IFG trigger
      __data16_write_addr((unsigned short) &DMA0SA,(unsigned long) &ADC10MEM0);       // Source single address
                                               
      __data16_write_addr((unsigned short) &DMA0DA,(unsigned long) 0xF200);                      // Destination array address
                                              
      DMA0SZ = 0x578;                                                                                                                            // Number of conversions is 1400
      DMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAIE + DMALEVEL;
                                                                                                                                                                 // Rpt, inc dest, word access,
                                                                           

       DMACTL0 += DMA1TSEL__ADC10IFG;            // ADC10IFG trigger
      __data16_write_addr((unsigned short) &DMA1SA,(unsigned long) &ADC10MEM0);      // Source single address
                                               

     __data16_write_addr((unsigned short) &DMA1DA,(unsigned long) 0xF900);                    // Destination array address
                                               
      DMA1SZ = 0x578;                                                                                                                           // Number of conversions is 1400
      DMA1CTL = DMADT_4 + DMADSTINCR_3 + DMAIE + DMALEVEL;


    DMA0 works fine, and after 1400 transfers it triggers its interrupt. However DMA1 does not do the same. The problem seems to be the destination address of DMA1 (above bold). If  I adjust the assigned memory  to any value between F180 - F499 then the correct interrupt occurs. All of these addresses are in the wrong buffer (buffer0), which means that this is useless to me. I cannot assign any memory address inside of buffer1. When I build the code I get no errors from the compiler, so I am not sure what the problem is.

    I have even tried to declare two arrays inside the buffers like this:

    #ifdef __CCS__
    #pragma DATA_SECTION(buffer0_Array, ".fram_adc_buf0")
    char buffer0_Array[SENDING_PACKETS];

    #pragma DATA_SECTION(buffer1_Array, ".fram_adc_buf1")
    char buffer1_Array[SENDING_PACKETS];

    #endif

    And then assigning the DMA addresses like this:

     __data16_write_addr((unsigned short) &DMA1DA,(unsigned long) &buffer1_Array);

    However I had the same problem.

    I cant seem to address the memory in buffer 1, and I get no compiler issues. Why am I getting these problems? Am I addressing the memory in the assigned buffers correctly (linker command file)?

    I have modified the DMA demo code "MSP430FR57xx_adc10_15" provided by CCS5:

    #include "msp430fr5739.h"
    #include <stdio.h>
    
    void really_long_time (void);
    int samplePackets = 10;
    
    
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      // Configure SMCLK = 1MHz
      //****************************************************************************************************************************************
      //Config the clock
      CSCTL0_H = 0xA5;
      CSCTL1 |= DCOFSEL0 + DCOFSEL1;             // Set max. DCO setting
      CSCTL2 = SELA_1 + SELS_3 + SELM_3;        // set ACLK = VLO; MCLK = DCO
      CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0;        // set all dividers 					//Can be made faster
     
      //****************************************************************************************************************************************
      //Config the ADC
      // Configure ADC10; 
      ADC10CTL0 = ADC10SHT_3 + ADC10MSC + ADC10ON;                    					//32 Clock Cycles in sample, Continous Saample, Adc On
      ADC10CTL1 = ADC10SHP + ADC10CONSEQ_2 + ADC10SSEL_3 + ADC10DIV_0;               	//Repeat Single Channel, Sm Clock, Divide clock by 2
                                                // Sampling timer, rpt single ch
    //  ADC10CTL2 = ADC10RES;                     // 10-bit resolution
      ADC10CTL2 &= ~ADC10RES;
      ADC10MCTL0 = ADC10INCH_11 + ADC10SREF_1;  // Vref+, A10
    
     //****************************************************************************************************************************************
     // Configure internal reference
      while(REFCTL0 & REFGENBUSY);              // If ref generator busy, WAIT
      REFCTL0 |= REFVSEL_3+REFON;               // Select internal ref = 2.5V 
                                                // Internal Reference ON   
      __delay_cycles(75);                       // Delay (~75us) for Ref to settle
    
      //****************************************************************************************************************************************
      // Configure DMA (ADC10IFG trigger)
    
       DMACTL0 = DMA0TSEL__ADC10IFG;            // ADC10IFG trigger
      __data16_write_addr((unsigned short) &DMA0SA,(unsigned long) &ADC10MEM0);
                                                // Source single address
      __data16_write_addr((unsigned short) &DMA0DA,(unsigned long) 0xF200);
    //  DMA0DA = (__SFR_FARPTR)0xF200;
                                                // Destination array address
      DMA0SZ = 0x578;                            // Number of conversions is 1400
      DMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAIE + DMALEVEL;
                                                // Rpt, inc dest, word access,
                                                // enable int after 32 conversions
    
       DMACTL0 += DMA1TSEL__ADC10IFG;            // ADC10IFG trigger
      __data16_write_addr((unsigned short) &DMA1SA,(unsigned long) &ADC10MEM0);
                                                // Source single address
      __data16_write_addr((unsigned short) &DMA1DA,(unsigned long) 0xF200);
    //  DMA1DA = (__SFR_FARPTR)0xF500;
                                                // Destination array address
      DMA1SZ = 0x578;                            // Number of conversions is 1400
      DMA1CTL = DMADT_4 + DMADSTINCR_3 + DMAIE + DMALEVEL;
    
    
        P3OUT &= ~(BIT4 + BIT5 + BIT6 + BIT7);
        P3DIR |= (BIT4 + BIT5 + BIT6 + BIT7);
    	P3OUT ^= 0xF0;
    	DMA1CTL += DMAEN;
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	really_long_time ();
    	P3OUT ^= 0xF0;
    
    	ADC10CTL0 |= ADC10ENC + ADC10SC;        // Start sampling
    	__bis_SR_register( GIE);        // LPM0, ADC10_ISR will force exit
      while(1)
      {
        while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
        __no_operation();
    	P3OUT ^= 0x40;
      }
    }
    
    #pragma vector=DMA_VECTOR
    __interrupt void DMA0_ISR (void)
    {
      switch(__even_in_range(DMAIV,16))
      {
        case  0: break;                          // No interrupt
        case  2: 
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          P3OUT ^= 0xF0;
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          really_long_time ();
          P3OUT ^= 0xF0;
          break;                                 // DMA0IFG
        case  4:
            really_long_time ();
            really_long_time ();
            P3OUT ^= 0xA0;
            really_long_time ();
            really_long_time ();
            P3OUT ^= 0xA0;
            break;                          // DMA1IFG
        case  6: break;                          // DMA2IFG
        case  8: break;                          // Reserved
        case 10: break;                          // Reserved
        case 12: break;                          // Reserved
        case 14: break;                          // Reserved
        case 16: break;                          // Reserved
        default: break; 
      }   
    }
    
    void really_long_time (void){
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);                   // Delay between sequence convs
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
        __delay_cycles(25000);
    
    }
    
    

    Line 64 is where I select which DMA to enable. This code will now blink the MSP430FR5739 experimenters board differently depending on which DMA is enabled.


    Any advice would be greatly appreciated.

    Thanks

    Carson McAfee


  • Apologies.

    I made a setup mistake! Both DMA channels can be configured to transport a word (16 bit) or a byte (8 bit). By default it moves a word. I had specified a buffer that could handle a maximum of 1792 bytes. Therefore when the DMA ran through 1400 iterations it wrote to 2800 bytes of consecutive memory. Therefore writing to the first buffer was OK, but when doing the same with the second buffer the process would attempt to write to memory addresses outside of the specified memory location. This overlap would run into the interrupt memory locations!

    As soon as I set the DMA to operate with byte operations (DMAxCTL+= DMADSTBYTE + DMASRCBYTE;) the code worked.

    Sorry if this wasted anyone's time.

    Carson