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.
Hello again...
I'm using CCS 6.1 on openSUSE 13.1. I always program microcontrollers in assembly, so my question is for the assembler of TI v4.4.4.
Suppose I have a file containing all the code for driving a real time clock chip through SPI. I created this file in a way to be able to define if the SPI bus is used only for this device or if the bus is shared with other SPI devices. So, I needed one definition to be global to the whole project, defining at which port lies the Chip Select pin. This is a must in order to create an interrupt dispatcher according to which SPI device is enabled. So much for the introduction of the problem.
When i create the definition:
RTCCTLOUT .equ P1OUT
and then
.global RTCCTLOUT
i get en error message "ERROR! at line 8: [E0300] Cannot equate an external symbol to an external symbol"
The problem can be reproduced using the following code (which is the default main assembly program the CCS created in an assembly-only project), together with the definitions that produce the problem:
;-------------------------------------------------------------------------------
; MSP430 Assembler Code Template for use with TI Code Composer Studio
;
;
;-------------------------------------------------------------------------------
.cdecls C,LIST,"msp430.h" ; Include device header file
RTCCTLOUT .equ P1OUT ;Control port of external Real Time Clock
.global RTCCTLOUT ;Must be global to othe files
;-------------------------------------------------------------------------------
.text ; Assemble into program memory
.retain ; Override ELF conditional linking
; and retain current section
.retainrefs ; Additionally retain any sections
; that have references to current
; section
.global RESET ; Entry point must be global
;-------------------------------------------------------------------------------
RESET mov.w #__STACK_END,SP ; Initialize stackpointer
StopWDT mov.w #WDTPW|WDTHOLD,&WDTCTL ; Stop watchdog timer
jmp $ ; Nothing else to do
;-------------------------------------------------------------------------------
; Main loop here
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; Stack Pointer definition
;-------------------------------------------------------------------------------
.global __STACK_END
.sect .stack
;-------------------------------------------------------------------------------
; Interrupt Vectors
;-------------------------------------------------------------------------------
.sect ".reset" ; MSP430 RESET Vector
.short RESET
What am I doing wrong?
Thank you for your help
Ilias
The problem is you are trying to create a symbolic constant out of a substitution symbol. The assembler does not support that.
Please read the sections titled Symbolic Constants and Substitution Symbols in the MSP430 assembly tools manual. It is important to understand the differences in those terms.
If you build your test case with the option -al, it creates a listing file with a file extension of .lst. Inspect this file to see this line ...
A 1408 .define "(PAOUT_L)",P1OUT
Look up the .define directive in the MSP430 assembly tools manual. You will see it creates a substitution symbol, and not a symbolic constant. This line in your code ...
Ilias Chrisocheris said:RTCCTLOUT .equ P1OUT
attempts to create a symbolic constant based on a substitution symbol. That doesn't work. You can only create another substitution symbol. You can do that with either the .asg directive or the .define directive. Substitution symbols cannot be global the way symbolic constants can. They have to be defined in a header file that is included in all the assembly files.
Another solution to consider ... Just use P1OUT everywhere you presently use RTCCTLOUT.
This analogy may help ... C #define symbols are like substitution symbols, and C global variable names are like symbolic constants.
Thanks and regards,
-George
The truth is that I could not understand the difference between .define and .equ/.set so I tried different things. Your answer clarifies their difference.
George Mock said:Another solution to consider ... Just use P1OUT everywhere you presently use RTCCTLOUT.
Well, this is not a solution cause RTCCTLOUT value is the result of preprocessor, according to settings to other definitions, so it cannot be substituted... Another solution I figured out is to make a file called definitions.asm that runs all the preprocessor commands and it could be included into every file that uses the library for the RTC. So, I wouldn't have to .global any definitions
What I've done after reading your answer is that by doing:
.define P1OUT,RTCCTLOUT
and then
.global RTCCTLOUT
the problem is solved (well, the program passes the building of this file, but I don't know if the final project works). So, until I finish this project and make it work I consider your answer as the solution to my problem. If I find any problem according to this question, of course I will post again :)
Thank you very much for your time and effort to help me in this project
Regards
Ilias
Well, unfortunately the final code does not pass linking... By doing
.global RTCCTLOUT
I found out that it expects RTCCTLOUT to be defined in another file, while I wanted it to be exported to other files... By doing
.def RTCCTLOUT
It says that P1OUT is not defined in this file, which, of course, is true. So, how can I define a symbol that can be referenced by other file and have a value of P1OUT?
To clarify my question, I add the preprocessor code that lies in my assembly file and defines some variables I need. Only RTCCTLOUT is the one I need to be referenced by another file:
;============================================================================================
; DEFINITIONS - This section contains all necessary definition visible only to this file
;--------------------------------------------------------------------------------------------
RTCSPI .equ "UCA0" ;The UCSI that communicates to RTC
RTCCtlPort .equ 1 ;The port the control pins of RTC are connected
;RTCIntPort .equ 1 ;Uncomment if RTC interrupt is on a different port
; than RTCCtlPort
RTC_IRQ .equ BIT4 ;Interrupt pin
RTC_CS .equ BIT3 ;Chip select pin
;...
;...
;...
;============================================================================================
; AUTO DEFINITIONS - This section contains definitions calculated by preprocessor, mainly
; according to the previously specified ones
;--------------------------------------------------------------------------------------------
.if (RTCCtlPort == 1)
RTCCTLIN .equ P1IN
.define P1OUT,RTCCTLOUT
RTCCTLDIR .equ P1DIR
RTCCTLSEL .equ P1SEL
RTCCTLREN .equ P1REN
.elseif (RTCCtlPort == 2)
RTCCTLIN .equ P2IN
.define P2OUT,RTCCTLOUT
RTCCTLDIR .equ P2DIR
RTCCTLSEL .equ P2SEL
RTCCTLREN .equ P2REN
.elseif (RTCCtlPort == 3)
RTCCTLIN .equ P3IN
.define P3OUT,RTCCTLOUT
RTCCTLDIR .equ P3DIR
RTCCTLSEL .equ P3SEL
RTCCTLREN .equ P3REN
.elseif (RTCCtlPort == 4)
RTCCTLIN .equ P4IN
.define P4OUT,RTCCTLOUT
RTCCTLDIR .equ P4DIR
RTCCTLSEL .equ P4SEL
RTCCTLREN .equ P4REN
.elseif (RTCCtlPort == 5)
RTCCTLIN .equ P5IN
.define P5OUT,RTCCTLOUT
RTCCTLDIR .equ P5DIR
RTCCTLSEL .equ P5SEL
RTCCTLREN .equ P5REN
.elseif (RTCCtlPort == 6)
RTCCTLIN .equ P6IN
.define P6OUT,RTCCTLOUT
RTCCTLDIR .equ P6DIR
RTCCTLSEL .equ P6SEL
RTCCTLREN .equ P6REN
.elseif (RTCCtlPort == 7)
RTCCTLIN .equ P7IN
.define P7OUT,RTCCTLOUT
RTCCTLDIR .equ P7DIR
RTCCTLSEL .equ P7SEL
RTCCTLREN .equ P7REN
.elseif (RTCCtlPort == 8)
RTCCTLIN .equ P8IN
.define P8OUT,RTCCTLOUT
RTCCTLDIR .equ P8DIR
RTCCTLSEL .equ P8SEL
RTCCTLREN .equ P8REN
.else
emsg "RTCCtlPort was not defined correctly!"
.endif
.def RTCCTLOUT
.def RTC_CS
The first part of the code defines hardware side connections. The rest (AUTO DEFINITIONS) define the rest of the symbols needed by the code and depend on the hardware design.
I know that a way to do it is to add another file called something like RTC_Definitions.asm that would contain all this preprocessor code (without .def lines) which should be included to every assembly code file uses the RTC library. But it would be much more comfortable if everything was in a single file, exporting only the necessary symbols...
Again, thanks everybody for your time
Ilias
Ilias Chrisocheris said:I know that a way to do it is to add another file called something like RTC_Definitions.asm that would contain all this preprocessor code (without .def lines) which should be included to every assembly code file uses the RTC library.
That's the only solution I can suggest.
Thanks and regards,
-George
Well, there is a drawback in that approach. You cannot easily take advantage of command line definitions. The real code I use is:
;============================================================================================
; DEFINITIONS - This section contains all necessary definition visible only to this file
;--------------------------------------------------------------------------------------------
.if $isdefed("RTCSPI") == 0 ;RTCSPI could be defined in command line
RTCSPI .equ "UCA0" ;The UCSI that communicates to RTC
.endif
.if $isdefed("RTCCtlPort") == 0 ;RTCCtlPort could be defined in command line
RTCCtlPort .equ 1 ;The port the control pins of RTC are connected
.endif
;RTCIntPort .equ 1 ;Uncomment if RTC interrupt is on a different port
; than RTCCtlPort. Could also be defined in CLI
.if $isdefed("RTC_IRQ") == 0 ;RTC_IRQ could be defined in command line
RTC_IRQ .equ BIT4 ;Interrupt pin
.endif
.if $isdefed("RTC_CS") == 0 ;RTC_CS could be defined in command line
RTC_CS .equ BIT3 ;Chip select pin
.endif
.if $isdefed("SHAREDBUS") == 0 ;SHAREDBUS could be defined in command line
SHAREDBUS .equ 1 ;Giving a value of 0 means that the bus is used
.endif ; only by this peripheral. A value of 1 means
; that SPI bus is shared with other peripherals
.if $isdefed("CPUSMCLK") == 0
CPUSMCLK .equ 16000000 ;The CPU SMCLK clock frequency in Hz
.endif
.if $isdefed("RTCRXBUFLEN") == 0 ;RTCRXBUFLEN could be defined in command line
RTCRXBUFLEN .equ 18 ;Size of incoming stream buffer
.endif
.if $isdefed("RTCTXBUFLEN") == 0 ;RTCTXBUFLEN could be defined in command line
RTCTXBUFLEN .equ 18 ;Size of outgoing stream buffer
.endif
I use this approach to be able to define some or all of those values through command line. If someone wants to have truly robust code then this is not the case because it can lead to inconsistencies during project building. Using the split file approach makes the usage of same definitions to all assembly commands in command line. Fail to do this can lead to have different definitions of the same thing in two different files of the project.
To make this more clear... Suppose you have a file called RTC.asm that contains all the functions needed to control an RTC chip. The file RTC_Defs.asm contains all the definitions and preprocessor functionality as the one I described in this thread. By including RTC_Defs.asm in RTC.asm everything is fine up to now. The problem starts when you want to change the port from UCA0 to UCA1. By assembling the file using -ad=RTCSPI="UCA1" everything is fine.
The same preprocessing RTC_Defs.asm should be included in main.asm in order for the interrupt dispatcher functions to redirect the interrupt to the correct ISR according to the current chip select active pin. If you forget to add -ad=RTCSPI="UCA1" also in main.asm then the interrupt service routine of RTC will be bind to the dispatcher of another interrupt vector, making the code unusable, the debugging almost impossible and the programmer start using to drugs :). As far as I found out is that even when defining something in the command line, for some, unknown to me, reason, it parses also the block inside an .if $isdefed... .endif firing an error... (checked by including -ad=RTC_CS=BIT7, well, to be honest I added the line RTC_CS=BIT7 in the properties of the file in assembler definitions)
To my opinion .equ or .set should be able to create a symbol using the value assigned to another symbol, such as RTCCTLOUT .equ P1OUT. All the assemblers I've used before (programming MSP Assembly since 2002) do it and I believe this is a real feature...
Anyway, I really thank you for your help and for your valuable time (I know it is)
Best regards
Ilias