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.

MSP430FR5969 Write/Read to/from FRAM [MSP430GCC]

Other Parts Discussed in Thread: MSP430FR5969

Dear All, 

I have been checking each and every question related to this problem including the user's guide, but I haven't been able to write to and read from FRAM in MSP430FR5969. If useful, I am not using TI CCS or IAR but msp430gcc. 

The (rather simple) code I am trying to run is as follows:

#define FRAM_START_ADDR 0xD000
#define FRAM_END_ADDR 0xE000

unsigned long *FRAM_write_ptr;
unsigned long data;

/*---------------------------------------------------------------------------*/
void
fram_write(void)
{
  data = 0x00000001;

  FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;

  PRINTF("Writing to 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);

  *FRAM_write_ptr = data;  

  PRINTF("Data %lu VS FRAM_write_ptr %lX \n", data, FRAM_write_ptr);
}
/*---------------------------------------------------------------------------*/
void
fram_read(void)
{
  FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;
  PRINTF("Reading from 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);
  data = *FRAM_write_ptr;
  PRINTF("FRAM_write_ptr %lX\n", data);
}
/*---------------------------------------------------------------------------*/

And the output I get is:

Writing to 0xD000
Data 1 VS FRAM_write_ptr FFFFFFFF
Reading from 0xD000
Data_write_ptr FFFFFFFF
...

Any help would be highly appreciated. Many thanks

Best wishes, 

David

  • Hi David,

    What is the state of the MPU? I know that you are not using CCS but your results are very similar to that of this thread: e2e.ti.com/.../485532

    It is possible that the MPU is enabled by default, setting the FRAM to read + execute access only and therefore not allowing for any writes. You could test this by clearing the MPUENA bit which disables the MPU and allows for complete memory access, although this is not advised as a general solution but rather a debugging tool.

    Regards,
    Ryan
  • The startup code in mspgcc does nothing to the MPU so that isn't the problem. I haven't tried to access the FRAM this way but I have configured FreeRTOS to use part of the FRAM as its heap and that worked just fine with gcc.

    I suggest adding "-Wall" to the gcc command line as I suspect that at the very least there are some type problems in the printf() calls.
  • I suggest that you try your code again with the first two lines changed to:

    #define FRAM_START_ADDR 0x1E00
    #define FRAM_END_ADDR 0x1F00

    Do not change anything else.

    This chip has 2KB of SRAM from 0x1C00 to 0x23FF. I assume that your code does not need all of that.

    In other words, I am asking "Can you read/write from/to SRAM?"

  • Hi @old_cow_yellow

    Thanks for your reply. The code effectively works when using the memory space available for SRAM. However, that's SRAM allocated space, therefore volatile, and I already use most of it.

    Since FRAM is a SRAM-like memory type, I expected to write to and read from FRAM as in a SRAM, and some people had mentioned this in other posts. 

    The FRAM address space where I am trying to write is supposed to be unrestricted, so it should be easy to use. But at this point I don't even know if I am actually writing. 

    Apart from the fact that I believe I am not accessing to FRAM correctly, I was wondering whether, for example, it is necessary to have the MCU completely on (no LPM) for any write/read operations. I have already tried this, but the result hasn't changed.

    Any help would be highly appreciated.  

    Best wishes, 

    David

  • Hi David, I will try this now, and will let you know asap.
  • Hi Ryan, I will try this now, and will let you know asap.
  • Hi All,

    I've tried your suggestions. I had -Wall already in my CFLAGS but apparently there is no problem. I have also tried to configure the MPU as follows (I include more code now):

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <inttypes.h>
    
    #define DEBUG 1
    #if DEBUG
    #include <stdio.h>
    #define PRINTF(...) printf(__VA_ARGS__)
    #define PRINTDEBUG(...) printf(__VA_ARGS__)
    #else
    #define PRINTF(...)
    #define PRINTDEBUG(...)
    #endif
    /*---------------------------------------------------------------------------*/
    #ifdef FRAM_START_ADDR_CONF
    #define FRAM_START_ADDR FRAM_START_ADDR_CONF
    #else
    #define FRAM_START_ADDR 0xE000
    #endif
    
    #ifdef FRAM_END_ADDR_CONF
    #define FRAM_END_ADDR FRAM_END_ADDR_CONF
    #else
    #define FRAM_END_ADDR 0xFFFF
    #endif
    /*---------------------------------------------------------------------------*/
    unsigned long *FRAM_write_ptr;
    unsigned long data;
    /*---------------------------------------------------------------------------*/
    static void
    fram_init(void)
    {
    
      /*
       * MPU segment boundaries:
       * Border 1 = 0x0E000 [MPUSEGB1 = 0x0E00]
       * Border 2 = 0x10000 [MPUSEGB2 = 0x1000]
       * Segment 1 = 0x0D000 - 0x0DFFF
       * Segment 2 = 0x0E000 - 0x0FFFF
       * Segment 3 = 0x10000 - 0x13EFF
       *
       * Segment 2 is write unprotected.
       */
    
      MPUCTL0_H = MPUPW_H;
      MPUSEGB1 = 0x0E00;
      MPUSEGB2 = 0x1000;
      MPUSAM = MPUSEG2WE | MPUSEG2RE;
      MPUCTL0_L &= ~(MPULOCK | MPUENA);
      MPUCTL0_H = 0;
    }
    /*---------------------------------------------------------------------------*/
    static uint8_t
    fram_write(uint32_t *writeAddress, const void *writeData)
    {
      data = 0x00000001;
    
      FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;
    
      PRINTF("Writing to 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);
    
      *FRAM_write_ptr = data;
      PRINTF("Data %lu VS FRAM_write_ptr %lX \n", data, *FRAM_write_ptr);
      return FRAM_SUCCESS;
    }
    /*---------------------------------------------------------------------------*/
    static uint8_t
    fram_read(uint32_t *readAddress, uint32_t *readData, uint16_t len)
    {
      FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;
      PRINTF("Reading from 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);
      data = *FRAM_write_ptr;
      PRINTF("FRAM_write_ptr %lX\n", data);
      return FRAM_SUCCESS;
    }
    /*---------------------------------------------------------------------------*/
    int main(int argc, char **argv)
    {
      msp430_init(); /* Initialize all msp430 pins (PxDIR = 0, PxOUT = 0, 
                      * PxSELx =0, PxREN = 0xFF) – each peripheral will 
                      * configure the necessary pins as required.
                      * Configure clock: ACLK = LFX, SMCLK = MCLK = DCO = 8MHz.
                      * Also, if SYSRSTIV == SYSRSTIV_LPM5WU, then PM5CTL0 &= ~LOCKLPM5
                      */
      uart1_init(115200); /* Configure UCA1 to use serial communication*/
    
      fram_init();
    
      while(1){
    
        /* Set timer to 1 second, after which we perform a FRAM write and a read operation */
        set_timer(1 second);
    
        // Here, mem_offset and write_buf are useless considering what I do in fram_write
        if(fram_write(&mem_offset, &write_buf) == FRAM_ERROR) { 
          PRINTF("Fail: Write to FRAM failed\n");
          exit(1);
        }
        // Here, mem_offset and read_buf are useless considering what I do in fram_write
        if(fram_read(&mem_offset, &read_buf, sizeof(read_buf)) == FRAM_ERROR) { 
          PRINTF("Fail: Read from FRAM failed\n");
          exit(1);
        }
      }
    }
    /*---------------------------------------------------------------------------*/

    And the output is:

    ...
    Writing to 0xE000
    Data 1 VS FRAM_write_ptr FFFFFFFF
    Reading from 0xE000
    FRAM_write_ptr FFFFFFFF
    ...

    Any ideas? Thanks in advance. 

    Best wishes, 

    David

  • Now it is trying to disable all execute accesses. I wonder how it can run at all.
  • Thank you for the prompt reply.

    I am not sure if you did try the modified code and is explaining that result. Or you are explaining the inevitable result and thus did not try the modified code. Could you confirm?

    Now, let us look at it at a different angle. One of the source code line is:

       FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;

    Is this line compiled into something like this?

       mov.w   #0xD000,&FRAM_write_ptr

    Another source code line:

       *FRAM_write_ptr = data;

    Is this line compiled into something like these?

       mov.w   &FRAM_write_ptr,R15

       mov.w   &data,0(R15)

       mov.w   &data+2,2(R15)

  • Hi All,

    Thanks for your help and sorry for the trouble :$

    Yeah, the code I included before is just to explain more or less what I intended to do. What I was trying to do however is, from what I understood from the user's guide, to allocate a specific address range (through memory segmentation) and enable write/read access. From Clemens's answer I doubt now that I was actually doing it right!

    Anyhow, in reply to old_cow_yellow, for example the function fram_write:

    uint8_t
    fram_write(uint32_t *writeAddress, const void *writeData)
    {
      data = 0x00000001;
    
      FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;
    
      PRINTF("Writing to 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);
    
      *FRAM_write_ptr = data;
      PRINTF("Data %lu VS FRAM_write_ptr %lX \n", data, *FRAM_write_ptr);
      return FRAM_SUCCESS;
    }

    is compiled as:

    uint8_t
    fram_write(uint32_t *writeAddress, const void *writeData)
    {
      data = 0x00000001;
       10598:	40 18 92 43 	movx	#1,	&0x020ae;r3 As==01
       1059c:	ae 20 
       1059e:	40 18 82 43 	clrx	&0x020b0	
       105a2:	b0 20 
    
      FRAM_write_ptr = (unsigned long *)FRAM_START_ADDR;
       105a4:	8f 00 00 e0 	mova	#0x0e000,r15	
       105a8:	60 0f aa 20 	mova	r15,	&0x020aa
    
      PRINTF("Writing to 0x%" PRIXPTR "\n", (uintptr_t)FRAM_write_ptr);
       105ac:	00 18 70 12 	pushx.a	#57344		;#0x0e000
       105b0:	00 e0 
       105b2:	01 18 70 12 	pushx.a	#79644		;#0x1371c
       105b6:	1c 37 
       105b8:	b0 13 0e 4b 	calla	#0x04b0e	
       105bc:	a1 00 08 00 	adda	#0x00008,r1	
    
      *FRAM_write_ptr = data;
       105c0:	2f 00 aa 20 	mova	&0x020aa,r15	
       105c4:	40 18 9f 42 	movx	&0x020ae,0(r15)	;0x00000(r15)
       105c8:	ae 20 00 00 
       105cc:	40 18 9f 42 	movx	&0x020b0,2(r15)	;0x00002(r15)
       105d0:	b0 20 02 00 
      PRINTF("Data %lu VS FRAM_write_ptr %lX \n", data, *FRAM_write_ptr);
       105d4:	2f 00 aa 20 	mova	&0x020aa,r15	
       105d8:	1f 12 02 00 	push	2(r15)		;0x0002(r15)
       105dc:	2f 12       	push	@r15		
       105de:	40 18 12 12 	pushx	&0x020b0	
       105e2:	b0 20 
       105e4:	40 18 12 12 	pushx	&0x020ae	
       105e8:	ae 20 
       105ea:	01 18 70 12 	pushx.a	#79662		;#0x1372e
       105ee:	2e 37 
       105f0:	b0 13 0e 4b 	calla	#0x04b0e	
       105f4:	a1 00 0c 00 	adda	#0x0000c,r1	
      return FRAM_SUCCESS;
    }

    I am starting to believe that it may be a problem of printf. Though I don't understand then when I tried with SRAM address space it worked! Also, shall I modify the MPU registers at all? What I was trying to do before does actually make any sense?

    Thanks, 

    David

  • I try to avoid using printf. But that does not mean I have any mistrust of it.

    Could you try to print out the contents of all MPU registers? (In 4 Hex digits.) They are all 16-bit registers. Their symbolic names are as follows.

    MPUCTL0, MPUCTL1, MPUSEGB2, MPUSEGB1, MPUSAM, MPUIPC0, MPUIPSEGB2, and MPUIPSEGB1.

    (If your header file does not have these symbolic names, their addresses are 0x05A0, 0x05A2, …, and 0x05AE respectively.)

  • You enabled read and write access to segment 2 but disabled all access to the other 2 segments so it is a good thing that you never enabled the MPU. At reset, the default values are to allow all access to every segment. To write protect a segment you need to clear the appropriate bit. This is how I protected my code and the vectors in assembly:

            mov     r9,&MPUSEGB1    ; B1 = CTOP
            bic     #MPUSEG1WE,&MPUSAM ; write protect segment 1
            
            mov     #0xfc0,&MPUSEGB2 ; B2 = 0xfc00 (segment 3 is upper mem)
            bic     #MPUSEG3WE,&MPUSAM ; write protect segment 3
            
            mov     #MPUPW+MPUENA+MPUSEGIE,&MPUCTL0 ; Enable MPU
            mov.b   #0,&MPUCTL0_H   ; disable MPU access
     

  • Hi,

    I am sorry but I would need advice to print out the MPU registers. I am trying to do it in C, trying to embed assembly code or any other options I am finding on google to print out the correct value of each MPU register. What I get so far is 0 for each of them, but I know that's not right as I am modifying some of them, and the result is (obviously) zero.

    Again, sorry for the trouble.

    David
  • printf("MPUXXX: %04x\n", MPUXXX);
  • Hi,

    That's actually what I did first, and the result was 0x0000 for every register. Then I started looking at google to see whether there was a special way to read from registers, and I got immerse in assembly code ad various options to end up doing nothing in the end as the result didn't change.

    I will install CCS on Monday and will play with it. Thanks All for you kind help. I will update with more news.

    David

  • More and more, it sounds like you are testing a simulator. And it is not very good one.
  • Hi,

    I am indeed using a simulator, but I was trying to make this work testing the real hardware.

    I made the code work in CCS after fixing a few issues. The code is very very simple. If useful for anyone:

    #define MMIO32(x)   (*(volatile unsigned long *)(x))
    /*---------------------------------------------------------------------------*/
    uint8_t
    fram_write(uint32_t writeAddress, const void *writeData)
    {
      if( (writeAddress < FRAM_START_ADDR) || (writeAddress > FRAM_END_ADDR) ) {
        PRINTF("%s:: not valid address\n", __FUNCTION__);
        return FRAM_ERROR;
      }
      MMIO32(writeAddress) = *(uint32_t*)writeData;
      return FRAM_SUCCESS;
    }
    /*---------------------------------------------------------------------------*/
    uint8_t
    fram_read(uint32_t readAddress, uint32_t *readData)
    {
      if( (readAddress < FRAM_START_ADDR) || (readAddress > FRAM_END_ADDR) ) {
        PRINTF("%s:: not valid address\n", __FUNCTION__);
        return FRAM_ERROR;
      }
      *readData = MMIO32(readAddress);
      return FRAM_SUCCESS;
    }
    /*---------------------------------------------------------------------------*/

    I started digging a bit more in the OS environment I am using to program the msp430. I found a problem that I don't know exactly how it is related: the CFLAGS/LDFLAGS I was using to enable 20-bit support. I made a port to work with this msp430 in such OS environment, and it seems I had the CFLAGS/LDFLAGS messed up. Now it works, finally. 

    I am really grateful for your help, but also very sorry for bothering you so much with all of this. 

    David

**Attention** This is a public forum