Usage of Xilinx built-in UART function #define XUartPs_IsReceiveData (BaseAddress ) - c

So I am trying to use this built-in UART function (from the Vitis SDK from Xilinix) to determine if there is a valid byte to read over UART. I created this function to return 1 if there was a byte to read or 0 if there wasn't
u32 UartHasMessage(void){
if(XUartPs_IsReceiveData(&XUartPs_Main)){
return 1;
}
else{
return 0;
}
}
However, even when there is a byte to read over UART, this function always returns false.
The weird behavior I am experiencing is when I step through the code using the debugger, I call UartHasMessage() to check if there is a byte to read, and it returns false, but in the next line I call a function to read a byte over UART and that contains the correct byte I sent over the host.
u32 test - UartHasMessage();
UartGetByte(&HostReply);
How come this UartHasMessage always returns false, but then in the next line I am able to read the byte correctly?

Caveat: Without some more information, this is a bit speculative and might be a comment, but it is too large for that.
The information below comes from the Xilinx documentation on various pages ...
XUartPs_RecvByte will block until a byte is ready. So, no need to call XUartPs_IsReceiveData directly (I think that XUartPS_RecvByte calls it internally).
A web search on XUartPs_Main came up with nothing, so we'd need to see the definition you have.
Most Xilinx documentation uses UART_BASEADDRESS:
#define UART_BASEADDR XPAR_XUARTPS_0_BASEADDR
I found a definition:
#define XPAR_XUARTPS_0_BASEADDR 0xE0001000
You might be better off using a more standard method, such as calling the XUartPs_LookupConfig function to get the configuration table entry which has all relevant values.
I'm guessing that you created the XUartPS_Main definition.
But, based on what you posted, (needing &XUartPS_Main instead of XUartPS_Main), it is linked/loaded at the exact address of the UART register bank. Let's assume that address is (e.g.) 0x10000. So, we might have:
u32 XUartPS_Main __attribute__(at(0x10000));
The at is an extension that some build systems support (e.g. arm) that forces the variable to be loaded at a given address. So, let's assume we have that (even if the mechanism is slightly different (e.g.):
__attribute__((section(".ARM.__at_0x10000")))
The definition of XUARTPS_SR_OFFSET is:
#define XUARTPS_SR_OFFSET 0x002CU
Offsets are [typically] byte offsets.
Given:
#define XUartPs_IsReceiveData(BaseAddress) \
!((Xil_In32((BaseAddress) + XUARTPS_SR_OFFSET) & \
(u32)XUARTPS_SR_RXEMPTY) == (u32)XUARTPS_SR_RXEMPTY)
Now if the definition of XUartPS_Main uses u32 [as above], we may have a problem because XUARTPS_SR_OFFSET will be treated as a u32 index and not a byte offset. So, it will access the wrong address.
So, try:
XUartPs_IsReceiveData((unsigned char *) &XUartPs_Main)
But, if it were me, I'd rework things to use Xilinx's standard definitions.
UPDATE:
Hi so XUartPs_main is defined as static XUartPs XUartPs_Main; I use it in a variety of functions such as a function to send bytes over uart and I call it by its address like I did with this function, all my other functions work as expected except this one. Is it possible it is something to do with the way the fifo works? –
29belgrade29
No, not all the API functions are the same.
The struct definition is [I synthesized this from the API doc]:
typedef struct {
u16 DeviceId; // Unique ID of device.
u32 BaseAddress; // Base address of device (IPIF)
u32 InputClockHz;
} XUartPs;
Somewhere in your code you had to initialize this with:
XUartPs_Main = XUartPs_ConfigTable[my_device_id];
Or, with:
XUartPs_Main = *XUartPs_LookupConfig(my_device_id);
If an API function is defined as (e.g.):
void api_dosomething(XUartPs_Config *cfg,...)
Then, you call it with:
api_dosomething(&XUartPs_Main,...);
So, most functions probably take such a pointer.
But, XUartPs_IsReceiveData does not want a pointer to a XUartPs_Config struct. It wants a base address. This is:
XUartPs_Main.BaseAddress
So, you want:
XUartPs_IsReceiveData(XUartPs_Main.BaseAddress)

Related

Keil uVision - Atmel SAM3U Read Unique Identifier

I've been trying to read the Unique Identifier (UID) from a Atmel SAM3U MCU, but it's proven more difficult than it needs to be to make it happen. Does anyone have any examples or can suggest how to read it properly? Whenever I do, I wait in a do while loop (like the documentation states) for the EEFC (Flash ROM) status register to change states, but it never does so the MCU is then stuck in a loop.
Here is the code I'm using
// must run this from SRAM
__attribute__((section(".ARM.__at_0x20080000"))) void Get_Unique_ID(unsigned int *pdwUniqueID)
{
Efc *p_efc;
unsigned int status;
// clear the array
pdwUniqueID[0] = 0;
pdwUniqueID[1] = 0;
pdwUniqueID[2] = 0;
pdwUniqueID[3] = 0;
// send the Start Read Unique Identifier command (STUI) by writing the Flash Command Register with the STUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
// wait for the Flash Programming Status Register (EEFC_FSR) to fall
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
// the Unique Identifier is located in the first 128 bits of the Flash memory mapping
pdwUniqueID[0] = *(unsigned int *)IFLASH0_ADDR;
pdwUniqueID[1] = *(unsigned int *)(IFLASH0_ADDR + 4);
pdwUniqueID[2] = *(unsigned int *)(IFLASH0_ADDR + 8);
pdwUniqueID[3] = *(unsigned int *)(IFLASH0_ADDR + 12);
// to stop the Unique Identifier mode, the user needs to send the Stop Read unique Identifier
// command (SPUI) by writing the Flash Command Register with the SPUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_SPUI;
// when the Stop Read Unique Unique Identifier command (SPUI) has been performed
// the FRDY bit in the Flash Programming Status Register (EEFC_FSR) rises
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
}
Note that __attribute__((section(".ARM.__at_0x20080000"))) isn't the best method to dynamically assign this function to SRAM via the linker and any suggestions on how to make it more dynamic would be appreciated.
SOLVED The problem was the chips I had were fake so SAM-BA was returning whatever was at the SRAM buffer address it specified. It's a bug in SAM-BA since if it received 0x00000000, it should give an error or warning message and then stop reading. Do not buy fake chips from China!
Thanks.
I don't believe p_efc is correctly initialized.
You create a pointer to a Efc datastructure which thus points to something.
You then write something to somewhere and are expect it to work.
Efc *p_efc;
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
My guess would be that you need to intialize it to the correct EEFC base address. The datasheet has the following to say:
The SAM3U4 (256 Kbytes internal Flash
version) embeds two EEFC (EEFC0 for Flash0 and EEFC1 for Flash1)
whereas the SAM3U2/1 embeds one EEFC.
So depending on your MCU version you need to address EEFC0 or EEFC1. I'm assuming that you use libopencm3 but this will work for any other library. Look for the EEFC location define. Following the defines/files/links we get to this page, it tells us to point our Efc pointer to EEFC0_BASE or EEFC1_BASE. I would advise you to use the EEFC0 and EEFC1 defines though as it makes your code portabler.
So your code should work if your Efc is located in EEFC0 if you do:
Efc *p_efc = EEFC0;

Function pointer in struct not working?

I have a driver and code that works on IAR but does not work for Atmel Studio 7. I get an error ld returned 1 exit status and undefined reference to '_read' (or _write) when I try to assign a function to a pointer inside a struct.
In the driver that I need to use there are two pointers defined as follows:
#define BMM050_WR_FUNC_PTR \
s8 (*bus_write)(u8, u8, \
u8 *, u8)
#define BMM050_RD_FUNC_PTR \
s8 (*bus_read)(u8, u8, \
u8 *, u8)re
In the file they have a struct defined as follows:
struct bmm050_t {
u8 company_id;/**<mag chip id*/
u8 dev_addr;/**<mag device address*/
BMM050_WR_FUNC_PTR;/**< bus write function pointer*/
BMM050_RD_FUNC_PTR;/**< bus read function pointer*/
void (*delay_msec)(BMM050_MDELAY_DATA_TYPE);/**< delay function pointer*/
s8 dig_x1;/**< trim x1 data */
s8 dig_y1;/**< trim y1 data */
s8 dig_x2;/**< trim x2 data */
s8 dig_y2;/**< trim y2 data */
u16 dig_z1;/**< trim z1 data */
s16 dig_z2;/**< trim z2 data */
s16 dig_z3;/**< trim z3 data */
s16 dig_z4;/**< trim z4 data */
u8 dig_xy1;/**< trim xy1 data */
s8 dig_xy2;/**< trim xy2 data */
u16 dig_xyz1;/**< trim xyz1 data */
};
In my application I try to do:
bmm050.bus_write = i2c_write;
bmm050.bus_read = i2c_read;
My functions are defined as:
int8_t i2c_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
int8_t i2c_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
EDIT: I am attaching the error code as asked:
c:/program files (x86)/atmel/studio/7.0/toolchain/arm/arm-gnu-toolchain/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/lib/armv6-m\libc.a(lib_a-writer.o): In function `_write_r':
C:\Users\aba\Documents\Atmel Studio\7.0\Project1\Project1\Debug\writer.c(1,1): error: undefined reference to `_write'
c:/program files (x86)/atmel/studio/7.0/toolchain/arm/arm-gnu-toolchain/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/lib/armv6-m\libc.a(lib_a-readr.o): In function `_read_r':
C:\Users\aba\Documents\Atmel Studio\7.0\Project1\Project1\Debug\readr.c(1,1): error: undefined reference to `_read'
collect2.exe(0,0): error: ld returned 1 exit status
I am guessing that your i2c_write and i2c_read functions call printf, write, putc, puts, or a similar function. Yes?
The errors you are seeing are the wrappers _write_r and _read_r trying to invoke the underlying write and read functions, and not being able to find them. See, e.g., this discussion (sec. 6.4) of implementation of these functions in the newlib C library.
The errors disappear when you comment out the bmm050.bus_write = i2c_write and bmm050.bus_read = i2c_read lines because nothing else in your code calls read or write. If you don't reference i2c_read in your code, such as when those lines are commented out, the linker can remove i2c_read from the compiled object file. Without i2c_read, there is no need for _read_r or read, so you don't get the linker errors.
So what to do?
A few options, in the order I would try them.
Call your board-support-package (BSP) vendor if you have a support contract.
Search through the Atmel Studio source/libraries to see if they provide a _read or _write implementation for your particular hardware. If Atmel Studio includes a BSP for your board, that may include the functions. (I don't have Atmel Studio myself, and probably wouldn't have the same BSP even if I did, so I can't tell you more specifically than that where to look.)
Note that those functions may be called read() and write() (without the leading underscore) if they are written in C. C compilers generally add a leading underscore to exported names.
Modify your i2c_read and i2c_write so they access the device's I2C registers directly. If you can eliminate calls the C library's I/O routines from those functions, you will no longer need _read or _write.
If you can't find an existing implementation or eliminate the need for one, look online for implementations. For example, this blog post (in German) includes a sample implementation of _write. That, plus the links below it in the thread, may help you (even if you don't speak German).
Finally, if necessary, roll your own _read and _write that will do some meaningful input and output on your particular target. I gather that's I2C, but you might at some point want that to be UART, LCD, seven-segment display, Nixie, or something else — write whatever I/O routines you wish! Note that this basically involves the same type of work as #3, but in a different context.
See also:
this answer, which relates to a similar situation on a different platform
this discussion of implementing your own OS (effectively) in order for _write_r to have something to talk to!

How to determine the size of a PIM within an AUTOSAR Runnable?

How can I determine the size of a PIM (Per Instance Memory) in c from inside a Runnable (without looking it up in the generated RTE and adding a fix value)?
Situation:
Runnable Foo has access to two PIMs Pim1 and Pim2. In the example the data from Pim1 shall be copied to Pim2.
Not only because of security and safety I need to check the size of both PIMs in order NOT to overwrite illegal data areas.
I know that the size of the PIM is configured in the SW-C description (SWCD). But as the SWCD may be changed after code implementation and in order to keep the code of the Runnable more generic, the size checking should not be based on fix values.
I also considered the problem of the sizeof for an array:
How to find the 'sizeof'(a pointer pointing to an array)?
For the PIMs the following code is generated by the RTE-Generator:
In Rte_Type.h
typedef uint8 Rte_DT_DtImplRec1_0;
typedef uint16 Rte_DT_DtImplRec1_1;
typedef struct
{
Rte_DT_DtImplRec1_0 var1;
Rte_DT_DtImplRec1_1 var2;
Rte_DT_DtImplRec1_2 var3;
} DtImplRec1;
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5];
In Rte.c
VAR(DtImplRec1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim1;
VAR(DtImplAry1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim2;
In Rte_FOO.h
#define Rte_Pim_Pim1() (&Rte_FOO_Pim1)
#ifdef RTE_PTR2ARRAYBASETYPE_PASSING
# define Rte_Pim_Pim2() (&((*RtePim_Pim2())[0]))
#else
# define Rte_Pim_Pim2() RtePim_Pim2()
#endif
#define RtePim_Pim2() (&Rte_FOO_Pim2)
Note that the define for array PIMs might also be changing, depending on the RTE_PTR2ARRAYBASETYPE_PASSING “switch”.
The following “access” is generated for the FOO template:
DtImplRec1 *Rte_Pim_Pim1(void);
Rte_DT_DtImplAry1_0 *Rte_Pim_Pim2(void)
The code for the Foo-Runnable may look like this:
FUNC(void, FOO_CODE) Foo(void)
{
DtImplRec1 *pim1 = Rte_Pim_Pim1();
Rte_DT_DtImplAry1_0 *pim2 = Rte_Pim_Pim2();
uint8 sizeOfPim1a = sizeof(Rte_Pim_Pim1()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim1b = sizeof(*Rte_Pim_Pim1()); /* evaluates to 6 */
uint8 sizeOfPim1c = sizeof(DtImplRec1); /* evaluates to 6 */
uint8 sizeOfPim1d = sizeof(Rte_FOO_Pim1); /* evaluates to 6 */
uint8 sizeOfPim2a = sizeof(Rte_Pim_Pim2()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim2b = sizeof(*Rte_Pim_Pim2()); /* evaluates to 1 */
uint8 sizeOfPim2c = sizeof(Rte_DT_DtImplAry1_0); /* evaluates to 1: sizeof(uint8) */
uint8 finalSize = MIN(sizeOfPim1b, sizeOfPim2b);
memcpy( pim2, pim1, finalSize ); /* (use of) memcpy is not the topic here */
}
To make my problem more "visible", here is a Callback-Runnable example for writing a DID via diagnostics:
FUNC(Std_ReturnType, FOO_CODE)
DataServices_Data_FFFF_WriteData(P2CONST(uint8, AUTOMATIC, RTE_APPL_DATA) Data, Dcm_OpStatusType OpStatus, P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, RTE_APPL_DATA) ErrorCode)
{
Std_ReturnType ret = E_NOT_OK;
#define sizeOfPim1 (5) /* how to determine the PIM size here if we do not know anything about it here? (PIM structure can change without modifying the code here) */
#define sizeOfDidFFFF (5) /* This is even another problem: How to determine the size of a DID. I will create another discussion thread for this question. */
/* Instead of this if-condition, an assert during compile-time would also be appropriate */
if( sizeOfPim1 == sizeOfDidFFFF )
{
/* We have to make sure that we do not copy more bytes as of the size of Pim1 */
memcpy( Rte_Pim_Pim1(), Data, sizeOfPim1 ); /* (use of) memcpy is not the topic here */
ret = E_OK;
}
return ret;
}
I don't have here any AUTOSAR environment to test this, so, please, if you try any of this, just let me know if it works. Besides, I am not an expert and it is quite a long time I don't write AUTOSAR code, so I will probably be missing something. I also don't want to publicize any RTE generator from any vendor, so I will cite only the standard.
Use sizeof(DtImplAry1)
You define that type and give it as input to the RTE generator, so you know the name. If your SWC doesn't make explicit use of that type the RTE generator could not include it in your .h, but you could add it manually to you SWC arxml. I think all tools out there allow to do this without having to edit the arxml by hand, just look for the option to include additional SWC types in your tool.
Use Instance API to access SWC data
The standard specifies a variable of type Rte_CDS_FOO to hold all pointers to PIMs of the SWC (among other things) if you enable the API (look for it in your tool).
Besides, a variable Rte_Inst_FOO should be available to you, declared as extern in your header. You could do sizeof(*Rte_Inst_FOO->Pim_Pim2).
EDIT: reply to some of your comments
I guess the reason you don't find the CDS is because of this (from Specification of RTE, 4.2.2, 5.4 RTE Data Structures):
The [CDS and Instance handler] definitions only apply to RTE generators operating in compatibility mode – in this mode the instance handle and the component data structure have to be defined even for those (object-code) software components for which multiple instantiation is forbidden to ensure compatibility.
Also,
[SWS_Rte_03793] If a software component does not support multiple instantiation,the name of the component data instance shall be Rte_Inst_cts, where cts is the component type symbol of the AtomicSwComponentType. (SRS_Rte_00011)
So, when the RTE-generator adheres to this compatibility mode, those variables must be there. If you are using a vendor specific solution, well, try to tag the question with that vendor name also, hopefully somebody can answer.
Assert at compile time
I am not going to ask why you are doing this, but IMHO I think it does not sound right, does it makes sense for the receiving buffer to be smaller that the data to copy?. Maybe it is better to assert at compile time if the buffer is smaller than your struct. Or you could define your array instead to be a struct and cast it if needed (if your are following MISRA rules, maybe you will have problems with it, just check). Just for reference, compile time assertions can use sizeof.
You have several problems here:
a) your sizeof(*pim1) returns 6 because of padding, because you start with an uint8, the second is uint16, and I guess the 3rd ist also uint16.
That's, why you should rather sort them by type size/alignment .. biggest to smallest
uint32
uint16
uint8
Even though, the elements might not be ordered anymore, but it also decreases finally the gaps in memory created by the linker.
b) the pim2 is an array, you can not get the array len/size from the pointer.
But, you should have the Rte definition of DtImplAry1.
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5]; // <-- taken in through Rte_Foo_Type.h (includes Rte_Type.h
uint32 ary_len = sizeof(DtImplAry1) / sizeof(DtImplAry1[0]);

How to share variables between two functions without declaring it a global variable in C language

I've been reading through a lot of answers, and there are a lot of opinions about this but I wasn't able to find a code that answers my question (I found a lot of code that answers "how to share variables by declaring")
Here's the situation:
Working with embedded systems
Using IAR workbench systems
STM32F4xx HAL drivers
Declaring global variables is not an option (Edit: Something to do with keeping the memory size small, so local variables disappear at the end of scope but the global variable stay around. The local variables were sent out as outputs, so we discard them right away as we don't need them)
C language
in case this is important: 2 .c files, and 1 .h is included in both
Now that's out of the way, let me write an example.
file1.c - Monitoring
void function(){
uint8_t varFlag[10]; // 10 devices
for (uint8_t i = 0; i < 10; i++)
{
while (timeout <= 0){
varFlag[i] = 1;
// wait for response. We'll know by the ack() function
// if response back from RX,
// then varFlag[i] = 0;
}
file2.c - RX side
// listening... once indicated, this function is called
// ack is not called in function(), it is called when
// there's notification that there is a received message
// (otherwise I would be able to use a pointer to change
// the value of varFlag[]
void ack(uint8_t indexDevice)
{
// indexDevice = which device was acknowledged? we have 10 devices
// goal here is to somehow do varFlag[indexDevice] = 0
// where varFlag[] is declared in the function()
}
You share values or data, not variables. Stricto sensu, variables do not exist at runtime; only the compiler knows them (at most, with -g, it might put some metadata such as offset & type of locals in the debugging section -which is usually stripped in production code- of the executable). Ther linker symbol table (for global variables) can, and often is, stripped in a embedded released ELF binary. At runtime you have some data segment, and probably a call stack made of call frames (which hold some local variables, i.e. their values, in some slots). At runtime only locations are relevant.
(some embedded processors have severe restrictions on their call stack; other have limited RAM, or scratchpad memory; so it would be helpful to know what actual processor & ISA you are targeting, and have an idea of how much RAM you have)
So have some global variables keeping these shared values (perhaps indirectly thru some pointers and data structures), or pass these values (perhaps indirectly, likewise...) thru arguments.
So if you want to share the ten bytes varFlag[10] array:
it looks like you don't want to declare uint8_t varFlag[10]; as a global (or static) variable. Are you sure you really should not (these ten bytes have to sit somewhere, and they do consume some RAM anyway, perhaps in your call stack....)?
pass the varFlag (array, decayed to pointer when passed as argument) as an argument, so perhaps declare:
void ack(uint8_t indexDevice, uint8_t*flags);
and call ack(3,varFlag) from function...
or declare a global pointer:
uint8_t*globflags;
and set it (using globflags = varFlag;) at the start of the function declaring varFlag as a local variable, and clear if (using globflags = NULL;) at the end of that function.
I would suggest you to look at the assembler code produced by your compiler (with GCC you might compile with gcc -S -Os -fverbose-asm -fstack-usage ....). I also strongly suggest you to get your code reviewed by a colleague...
PS. Perhaps you should use GCC or Clang/LLVM as a cross-compiler, and perhaps your IAR is actually using such a compiler...
Your argument for not using global variables:
Something to do with keeping the memory size small, so local variables disappear at the end of scope but the global variable stay around. The local variables were sent out as outputs, so we discard them right away as we don't need them
confuses lifetime with scope. Variables with static lifetime occupy memory permanently regardless of scope (or visibility). A variable with global scope happens to also be statically allocated, but then so is any other static variable.
In order to share a variable across contexts it must necessarily be static, so there is no memory saving by avoiding global variables. There are however plenty of other stronger arguments for avoiding global variables and you should read A Pox on Globals by Jack Ganssle.
C supports three-levels of scope:
function (inside a function)
translation-unit (static linkage, outside a function)
global (external linkage)
The second of these allows variable to be directly visible amongst functions in the same source file, while external linkage allows direct visibility between multiple source files. However you want to avoid direct access in most cases since that is the root of the fundamental problem with global variables. You can do this using accessor functions; to use your example you might add a file3.c containing:
#include "file3.h"
static uint8_t varFlag[10];
void setFlag( size_t n )
{
if( n < sizeof(varFlag) )
{
varFlag[n] = 1 ;
}
}
void clrFlag( size_t n )
{
if( n < sizeof(varFlag) )
{
varFlag[n] = 0 ;
}
}
uint8_t getFlag( size_t n )
{
return varFlag[n] == 0 ? 0 : 1 ;
}
With an associated header file3.h
#if !defined FILE3_INCLUDE
#define FILE3_INCLUDE
void setFlag( size_t n ) ;
void clrFlag( size_t n ) ;
uint8_t getFlag( size_t n ) ;
#endif
which file1.c and file2.c include so they can access varFlag[] via the accessor functions. The benefits include:
varFlag[] is not directly accessible
the functions can enforce valid values
in a debugger you can set a breakpoint catch specifically set, clear or read access form anywhere in the code.
the internal data representation is hidden
Critically the avoidance of a global variable does not save you memory - the data is still statically allocated - because you cannot get something for nothing varFlag[] has to exist, even if it is not visible. That said, the last point about internal representation does provide a potential for storage efficiency, because you could change your flag representation from uint8_t to single bit-flags without having to change interface to the data or the accessing the accessing code:
#include <limits.h>
#include "file3.h"
static uint16_t varFlags ;
void setFlag( size_t n )
{
if( n < sizeof(varFlags) * CHAR_BIT )
{
varFlags |= 0x0001 << n ;
}
}
void clrFlag( size_t n )
{
if( n < sizeof(varFlags) * CHAR_BIT )
{
varFlags &= ~(0x0001 << n) ;
}
}
uint8_t getFlag( size_t n )
{
return (varFlags & (0x0001 << n)) == 0 ? 0 : 1 ;
}
There are further opportunities to produce robust code, for example you might make only the read accessor (getter) publicly visible and hide the so that all but one translation unit has read-only access.
Put the functions into a seperate translation unit and use a static variable:
static type var_to_share = ...;
void function() {
...
}
void ack() {
...
}
Note that I said translation unit, not file. You can do some #include magic (in the cleanest way possible) to keep both function definitions apart.
Unfortunately you can't in C.
The only way to do such thing is with assemply.

How does this sfrw(x,x_) macro work (msp430)?

I just ran into an interesting phenomenon with msp430f5529 (TI launchpad). After trying different approaches I was able to find a solution, but I don't understand what is going on here.
This code is part of a timer interrupt service routine (ISR). The special function register (SFR) TA0IV is supposed to hold the value of the interrupt number that triggered the ISR.
1 unsigned int index;
2
3 index = TA0IV; // Gives wrong value: 19874
4 index = *((volatile unsigned int *) TA0IV_); // Correct value: 4
TA0IV is defined with macros here:
5 #define sfrw_(x,x_) volatile __MSPGCC_PERIPHERAL__ unsigned int x __asm__("__" #x)
6 #define sfrw(x,x_) extern sfrw_(x,x_)
7 #define TA0IV_ 0x036E /* Timer0_A5 Interrupt Vector Word */
8 sfrw(TA0IV, TA0IV_);
What does this part of the first macro on line 5 do?
asm("__" #x)
Why is there no "x_" on the right hand side in the macro on line 5?
Last and most important question: Why does the usual typecasting on line 4 work as expected, but the one on line 3 doesn't?
BTW I use gcc-4.7.0.
Edit: More info
9 #define __MSPGCC_PERIPHERAL__ __attribute__((__d16__))
1) The # is a preprocessor "stringify" operator. You can see the impact of this using the -E compiler switch. Google "c stringify" for details.
2) Couldn't say. It isn't required that all parameters get used, and apparently whoever wrote this decided they didn't need it.
3) I'll take a shot at this one, but since I don't have all the source code or the hardware and can't experiment, I probably won't get it quite right. Maybe close enough for what you need though.
The first thing to understand is what the asm bit is doing. Normally (ok, sometimes) when you declare a variable (foo), the compiler assigns its own 'internal' name to the variable (ie _foo). However, when interfacing with asm modules (or other languages), sometimes you need to be able to specify the exact name to use, not allowing the compiler to mangle it in any fashion. That's what this asm is doing (see Asm Labels). So when you brush aside all the #define nonsense, what you've got is:
extern volatile __MSPGCC_PERIPHERAL__ unsigned int TA0IV __asm__("__TA0IV");
Since the definition you have posted is "extern," presumably somewhere (not shown), there's a symbol named __TA0IV that's getting defined. And since accessing it isn't working right, it appears that it is getting MIS-defined.
With the caveat that I HAVEN'T TRIED THIS, I would find this to be somewhat more readable:
#define TA0IV_ 0x036E
inline int ReadInterruptNumber()
{
int retval;
asm volatile("movl (%c1), %0": "=rm" (retval) : "i" (TA0IV_));
return retval;
}
FWIW.

Resources