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.

RM46L852: RM46L852

Part Number: RM46L852
Other Parts Discussed in Thread: HALCOGEN

Hello!

I have few questions regarding programming my RM46 microcontroller. This is a bit long post where I am trying to explain what I've done so far and the issues I am not certain of and I would need your help with these.

I have tried to program it without using HALCoGen and hence hit a giant wall that surpasses that of Great Wall of China (go figure, lol).

I want to point out that I do not want to use HALCoGen and I want to write everything down myself. If you are wondering why I will give you two reasons as I fear that the discussion will go 'USE THE HALCOGEN' way and I want to avoid it:

  1. I am used to writing everything down myself. I have never used software like this nor do I want to start using it (think of me as a granda who doesn't want to modernise and use a mobile phone);
  2. The biggest problem I have with HALCoGen is that it generates a lot of code that I find unnecessary and I do not want to skim through the generated code just to find what I need. I understand that using HALCoGen is easier than doing what I want to do myself, but it also limits you as you are left with a lot of code you might simply not understand or even care to understand.

So, let's just, for example, speak about me writing my own GPIO. I downloaded the technical reference manual (approx. 2000 page long - the longest one I read so far) to get myself familiar with what I need to write in each register to get the desired result. Let's say I want to turn on the GPIO. I need to use GIOGCR0 register. It says that if I write 1 on bit0 it will enable the GPIO. But what is extremely weird is that I am not getting any error and my program compiles as long as I write GIOGCR0 in .h file (I found this being weird latter). I get the warning, though: 'THIS DECLARATION HAS NO STORAGE CLASS OR TYPE SPECIFIER'. I haven't payed much attention to it at first, since I was working with Eclipse to program Arduino long time ago, and warnings arose with every register name. The fork when I started taking the warning seriously was when I started writing the function that utilises GIODIN. I can't really write that in header file, so I jumped out to write it in .c file whilst writing the function prototype in header file. What got me astonished is that I got two major errors. First one is that Code Composer Studio does not understand the uint32_t nor uint32 type. The second issue was that GIODIN register cannot be found. This got me wondering and so I decided to do the stupidest thing I could think of >> let's remove gio.c and write to GIODIN register in .h file, and so I got even more confusing result. Compilation passed with few warnings only. That is when I realised that compiler cannot find the memory address of the register which should have resulted in error, but it didn't. Weird, no?

Then I've decided to go to Google and try to find the library with defined memory locations of each and every register. There was none since everyone uses HALCoGen... It seems I'm the only weirdo out there and that's why were here. Then I've decided to pick the lengthy technical manual once again, since I have no other option then write my own register file for the first time ever, and I have no clue how to do this, so I need your help. What I firstly found was:

Table 2-3. Module Registers / Memories Memory-Map (continued)

GIO          PS[16]                 0xFFF7_BC00                      0xFFF7_BCFF                      256B                      256B                              Reads return zeros, writes have no effect

Let's also say that I have no clue what PS[16] should stand for or the explanation that it is memory select.

From this I realised that GIO port is addressed from 0xFFF7BC00 to 0xFFF7BCFF which is good but I can't do a lot with that information unless I know memory addresses of each register mapped in that location.

Next thing I noticed is, if I want to use GIODIR for PORTB offset 54h is given on table 25-1. of GIO Control Register. What is 'h' in this case of an offset? Does this affect anything?

What I want to know is if the address of that  register is 0xFFF7_BC54 and how do I specify that it should only be up untill 0xFFF7_BC58 which is the address where GIODIN register starts? I presume using uint32, since it is the length inbetween two registers, would help with the #define statement but Code Composer Studio still has no clue what uint32 is and that is annoying for a microcontroller based IDE not to know.


So far I haven't had the need to write this down myself, so I am not sure how to do this since I am still getting errors.

Let's say that I have gio_register.h file where I will write down:

#define GIOGCR0 ((uint32_t *) 0xFFF7BC00)

#define GIOINTDET ((volatile uint32_t *) 0xFFF7BC08)

#define GIOPOL ((unti32_t *) 0xFFF7BC0C)

.

.

.

#define GIODIRB ((uint32_t *) 0xFFF7BC54)

#define GIODINB ((volatile uint32_t *) 0xFFF7BC58)

.

.

.

#define GIOPSLB ((uint32_t *) 0xFFF7BC70)

Will this work? Do I need to specify that each register is volatile? I am not exactly sure of that. It looks to me like only registers that change in time like GIODIR need that, but like GIOGCR0 do not, since they are only initialised at the start. What do you think about this? I am not a fan of turning off optimisation if it does not need to be turned off although it won't have any noticeable results in this case since TI has amazing processor. When I was introduced to 'volatile' keyword for first time I was told: 'ADD IT EVERYWHERE JUST IN CASE'... I can't settle with that statement.

Apparently, even if this would work, I am still left with a problem that Code Composer Studio has no clue what uint32 is unlike some other IDEs for microcontrollers. I understand that uint32 is a typedef but why is it not being recognised by Code Composer Studio by default? What's to be done?

Also, I have to ask something else in reference with questions so far.
What I've seen in HALCoGen generated code is: #define gioREG   ((gioBASE_t *)0xFFF7BC00U)

Which is later referenced as, for example: gioREG->GCR0   = 1U;

Since GCR0 is a first member of typedef structure it reserves first 32 bits in that structure so it's address is 0xFFFF7BC00 without any doubt. But what is this U appended to address (0xfff7bc00U) and number that is assigned to the GCR0 member of gioREG (1U)? Does it have soemthing to do with that 'h' in offset (56h for example)? Does it mean UNSIGNED? Or what is it?


So, when assigning value to gioREG->GCR0 in case of HALCoGen generated code, are all four the same?

  1. gioREG->GCR0 = 0b0000'0000'0000'0000'0000'0000'0000'0001;
  2. gioREG->GCR0 = 0x01;
  3. gioREG->GCR0 = 1U;
  4. gioREG->GCR0 = 1.

If not what could be the differences?

And can the U from address be omitted? Are these two the same?

  1. 0xFFF7BC00U
  2. 0xFFF7BC00

On contrary to this solution from HALCoGen which seems elegant, I do not want to assign new volatile typedefs or even bit fields. I just want each register to be defined with its exact memory location and directly used, so this: #define GIODIN ((volatile uint32_t *) 0xSOME_ADDRESS) and then latter called like GIODIN = 0x01;

One more thing and I will conclude this, what is rather an essay. Since I know that Eclipse IDE does not support word CLASS, for example, unlike Microsoft Visual Studio for C programming, I am wondering does it support ' or _ for binary / octal / hexadecimal definitions, for example:

GIOGCR0 = 0b0000'0000'0000'0000'0000'0000'0000'0000;

or

#define REG_NAME ((uint8_t *) 0x1234_5678)

Will this pass without any error with Code Composer Studio?

Thank you in advance for reading all this and hopefully helping me with my problems!

  • Nemanja,

    I see questions related to the controller, to HALCoGen generated code, the compiler and to general C.

    I'll address the general C one:

    >  First one is that Code Composer Studio does not understand the uint32_t nor uint32 type.

    uint32_t defined in stdint.h and
    uint32 defined in HALCoGen generated HL_hal_stdtypes.h

    > And can the U from address be omitted? Are these two the same?
    > 0xFFF7BC00U
    > 0xFFF7BC00

    The U means that it is explicitly predefined as an UNSIGNED constant.
    The fact if a compiler treats it as an unsigned or signed when you don't specify the U suffix is a bit complex, 
    Dependent on size of the variable it fits in, architecture of the device you are programming, ...

    >  'THIS DECLARATION HAS NO STORAGE CLASS OR TYPE SPECIFIER'

    Are you trying to use a C++ construct in a C program?

  • Jan Cumps said:

    >  'THIS DECLARATION HAS NO STORAGE CLASS OR TYPE SPECIFIER'

    Are you trying to use a C++ construct in a C program?

    Thank you for your answer. I understand everything you wrote.

    Unfortunately, I think you misunderstood what happened with that warning. No, I am not using C++. That's why I tried explaining what I was doing, to avoid that confusion, so I'll try again in different manner.

    This warning is due to this line:

    GIOGCR0 = 0x01;

    In other words I am assigning value of 1 to GIOGCR0 register to turn it on. 
    As I have noted it seems that GIOGCR0 register cannot be found. When HALCoGen generates code it generates library called reg_gio.h among others where it stores memory addresses for registers using typedef struct.

    What I need to do now, not having that HALCoGen generated code is to create that location myself.

    When I write (I've included stdint.h):

    #define GIOGCR0 ((uint32_t *) 0xFFF7BC00
    or
    #define GIOGCR0 ((uint32_t *) 0xFFF7BC00U

    and then later say

    GIOGRC0 = 0x01;
    or
    GIOGCR0 = 1U;

    I am getting both warning and error.

    The warning stays unchanged >> 'THIS DECLARATION HAS NO STORAGE CLASS OR TYPE SPECIFIER'
    The error says >> 'uint32_t HAS ALREADY BEEN DECLARED IN THE CURRENT SCOPE'

    Now not only does it not understand what GIOGCR0 is, it does not interpret it as an address whatsoever.


    Any thoughts on how to fix this?

  • I've tested this construct with another compiler (GCC).

    your define "GIOGRC" is literally replaced with "((uint32_t *) 0xFFF7BC00)" in the code (edit: this happens by the pre-processor at the very start, before the compiler compiles the code)

    ((uint32_t *) 0xFFF7BC00 can't get an integrer assigned in C.

    ../main.c:106:31: error: lvalue required as left operand of assignment
         ((uint32_t*) 0xFFF7BC00)  = 0x01;

  • I completely understand what happens with a pre-processor definition, but what I can't get is how to send a value to a specific memory location so it works.

    Usually, there are libraries where these are defined, so you would just say DDRD = 0xFF for example with Arduino and it will work. With TI that is not an option since HALCoGen generates these libraries. I want to write them myself, so I need to assign a specific memory location to a literal. How would you do that with TI so it works well?
  • If you create a struct that holds a unit32_t, and make your pointer point to that, you can assign a value.

    in the header:

    typedef volatile struct GCR0
    {
        int GCR0;      /**< 0x0000: Global Control Register */
    } GCR0_t;
    
    #define GCR0REG ((GCR0_t *)0xFFF7BC00U)

    In your .c file:

        GCR0REG -> GCR0 = 0x01U;
  • untested, but it could work with a primitive as such:

    typedef volatile int GCR0_t;
    
    #define GCR0REG ((GCR0_t *)0xFFF7BC00U)
    
    // ....
    
    *GCR0REG = 0x01U;

  • Aye! Thanks for all the help! :) This works.

    Also, it works if I only do this:

    #define GIOGCR0 ((uint32 *) 0xFFF7BC00U)

    GIOGCR0 = 0x00;

    There is no problem anymore.

    So, the only problem was with uint32_t... :(

    Thank you so much once again! :)
  • ARM have written a document on how to write and structure register header files:

  • Nemanja Tomovic said:
    Aye! Thanks for all the help! :) This works.

    Also, it works if I only do this:

    #define GIOGCR0 ((uint32 *) 0xFFF7BC00U)

    GIOGCR0 = 0x00;

    There is no problem anymore.

    So, the only problem was with uint32_t... :(

    Thank you so much once again! :)

    My tests fail on this:

    #define GIOGCR0 ((uint32 *) 0xFFF7BC00U)
    
    GIOGCR0 = 0x00;

    in GCC: error: lvalue required as left operand of assignment

    in TI compiler: error #138: expression must be a modifiable lvalue

  • Try this:

    #define GIOGCR0 (*(uint32 *)0xFFF7BC00U)

    GIOGCR0 = 0x1;
  • Yes, that works.

    Tested on a TMS570LC43:

  • What's weird. I've just noticed. What I told you passed without any problem is true. There were no problems with:
    #define GIOGCR0 ((uint32 *)0xFFF7BC00U) whatsoever.
    But problem is when I try to use this register with .c file. Then it does not recognise it, but it recognises it in .h files.

    The same thing is with this solution you've just given me:

    #define GIOGCR0 (*(uint32 *)0xFFF7BC00U)

    Is that working for you well?
  • That mechanism from works for me. I've executed it on a Hercules and watched the register value change (see screen capture above)
  • I see that you are using HALCoGen based files. I am not, this is just what I have:

  • Also works when I put the #define in a header file, and assign the value in a C file. It compiles and runs.
  • That's a linker warning to point out that your linker definition file is not as expected.

  • I am not quite sure how it works for you. When I use it with .c file this is what happens.

  • You are missing a header file that tells the compiler what uint32 means (unsigned integer). Replace "uint32" with "unsigned int". So your declaration will look like:

    #define GIOGCR0 (*(unsigned int *)0xFFF7BC00U)
  • I'm also missing it here:

    And the compilation passes without any problems...

    If I change it to unsigned int, will it still allocate 32 bits of memory space or not?

  • a look ahead when continuing on the HALCoGen-less path:

    You will find that very likely, once you are able to load your binary to the controller, your program will not really  run.
    The Hercules is complex, and there are a number of registers that need to be set before starting main(). (check the HL_sys_core.asm and HL_sys_startup.c file for an impression of the code that runs before main() is called).
    You need to define and initialise the interrupt vector, make the parts where you load your code executable, set memory cache options, initialise PLL and clock domains, power domains, ...

    A brave exercise if you can complete it and control a GIO pin. 

  • Hahaha, thanks.

    Hopefully, once I get these registers to work I will have the basic setup I need.

    I understand I need to set the DMA controller and many other things, but I'd rather do that than use HALCoGen. It's something I can't quite comprehend and I am not sure if I am blind but I couldn't find a lot of information I needed about it. For starters, I wanted to use eQEP. When I tried to look at tutorials on how to use it there was none. But then, there were a lot of tutorials on how to use communication like UART, Ethernet and so on. So, I decided to go the hard way and try to code everything down myself.
  • I've made a blog on how to use eQEP with rotary encoders (with HALCoGen):

  • Thanks for it! I will definitely check whole blog.