I am attempting to pass a reference to an I/O pin as an function argument on a PIC24F MCU using C. For PICs, the device header file provides access to the i/o buffer registers via:
LATAbits.LATA2 = 0; // sets the pin (RA2 in this case) low.
if (PORTAbits.RA3) { // reads the state of the pin. (RA3)
I want to do something like this:
int main() {
Configure(); // Sets up peripherals, etc.
WaitForHigh(PORTAbits.RA3); // waits for pin RA3 to go hi.
...
return 0;
}
void WaitForHigh( ?datatype? pin_reference ) {
while( !pin_reference ); // Stays here until the pin goes hi.
}
So what datatype am I trying to pass here? And what's actually going on when I poll that pin? Below, I copy a relevant portion from the PIC24F device header that I'm using in case it helps.
#define PORTA PORTA
extern volatile unsigned int PORTA __attribute__((__sfr__));
typedef struct tagPORTABITS {
unsigned RA0:1;
unsigned RA1:1;
unsigned RA2:1;
unsigned RA3:1;
unsigned RA4:1;
unsigned RA5:1;
} PORTABITS;
extern volatile PORTABITS PORTAbits __attribute__((__sfr__));
Thank you in advance!
As an alternative to using a macro, a function can accept both the PORT register address (or latch register address, eg. LATA in the case of a pin configured for output) and the mask of the bit in the register that is needed. For example:
#include<p24FV32KA301.h> // defines both PORTA and _PORTA_RA3_MASK
void WaitForHigh( volatile unsigned int * port, pin_mask ) {
while( !(*port & pin_mask) ); // Stays here until the pin goes hi.
}
int main()
{
...
WaitForHigh( &PORTA, _PORTA_RA3_MASK ); // waits for pin RA3 to go hi.
...
return 0;
}
Please, note that the PORT bit values are obtained through a bit field, so, answering your question, you can't. Bit fields doesn't have address, so you cannot pass it as a pointer to a function.
Instead, you could use a Macro:
#define WaitForHigh(p) do{while(!(p));}while(0)
It is true that macros has it's draw backs on code readability, yet, given that proper care is taken, there are situations where they're the best solution. It is arguable if macro is the best solution in this Q&A, yet it is important to mention.
Thanks to the commenters for the suggestions to improve the macro safeness.
You can combine preprocessor processing with a function to get what you wan along with compile time checking of the symbols. For example:
#define PORT_FUNC(f, p, b) f(p, b)
#define WaitForHigh(p, b) PORT_FUNC(WaitForHighImp, &p, _ ##p## _ ##b## _MASK)
void WaitForHighImp(volatile unsigned* p, unsigned char mask)
{
while (!(*p & m))
;
}
int main()
{
WaitForHigh(PORTA, RA3);
}
The advantage of this approach is that you online say "PORTA" once and "RA3" once at the time of the call, you make sure the bit name is present in the port and that the bit is present.
Related
Please allow me to clarify the title:
I'm writing a function to connect 16x2 LCD pins to TM4C123G pins. Users should be able to select any TM4C123G pin they want. As the function writer, I need the user to pass the information of that pin to me so that I can connect the pins.
Now I know there are two ways to modify a pin:
Method 1: Reference the full register and AND/OR with a certain value:
// Want to set PE1 to high
#define GPIO_PORTE_DATA_R (*((volatile unsigned long *)0x400243FC))
GPIO_PORTE_DATA_R |= 0x02;
Method 2: Use bit-specific addressing and reference PE1:
// Want to set PE1 to high
#define PE1 (*((volatile unsigned long *)0x40024008))
PE1 = 0x02;
Now consider the function I need to write: the user has to pass two pieces of information to it -- 1) Which GPIO is used (Port E), and 2) Which bit is used (PE1 the second bit from low end).
My question: Is there a way for the user to just pass me a memory address and I can simply set it to 0x01 for high and 0x00 for low?
This is actually a generic question independent of its platform. The solution is also opinion-based. Anyway, below are my suggestions :)
As the user will only manage the GPIO, s/he doesn't need to be aware of the implementation details that cover the control of the underlying peripheral at a lower level. Hence, you may want to hide the implementation details by just providing some basic functions to the user as below
/* Header File */
int enableGpio(int gpioPort, int index);
int disableGpio(int gpioPort, int index);
You can also hide the macros that you use to handle the logic behind the operation by declaring them inside the source file.
/* Source File */
#define GPIO_PORTE_DATA_R (*((volatile unsigned long *)0x400243FC))
#define PE1 (*((volatile unsigned long *)0x40024008))
int enableGpio(int gpioPort, int index) { /* Implementation*/ }
int disableGpio(int gpioPort, int index) { /* Implementation*/ }
I would also recommend using enumerations for declaring GPIO ports instead of integers. By that, you can prevent making undefined calls to your functions.
That's all for now :)
I am writing a C program on Eclipse to communicate from my ARM Cortex M4-F microcontroller in I2C with its master, another MCU.
In my I2C library, I use a static global variable to store all the parameters of the communication (address, lenghts, data buffers). The issue is that a part (an array containing the data to be transmitted, which are 8 bits integers) of this variable gets modified when the interrupt (Start condition followed by the slave's address on the I2C bus) happens, even before executing the code I put the handler. It gets assigned to 8, whatever the initial value.
I tried to put breakpoints basically everywhere, and a watchpoint on the variable, the changes arises seemingly from nowhere, not in the while loop, and before the call to my_I2C_Handler(), so the interrupt is the cause apparently.
I also tried setting the variable as volatile, but that changed nothing.
I noticed one interesting thing: putting a printf of the array's data during my_I2C_Init() or my_SlaveAsync(), like so:
printf("%d\n", req.tx_data[0]);
corrects this problem, but why? I want to remove all prints after debugging.
#include <stdint.h>
#include "my_i2c.h"
void I2C1_IRQHandler(void)
{
printf("\nI2C Interrupt\n");
my_I2C_Handler(MXC_I2C1); // MXC_I2C1 is a macro for the registry used
}
int main(void)
{
int error = 0;
printf("\nStarting I2C debugging\n");
// Setup the I2C
my_I2C_Shutdown(MXC_I2C1);
my_I2C_Init(MXC_I2C1);
NVIC_EnableIRQ(I2C1_IRQn); // Enable interrupt
my_I2C_SlaveAsync(MXC_I2C1); // Prepare to receive communication
while (1)
{
LED_On(0);
LED_Off(0);
}
printf("\nDone testing\n");
return 0;
}
The structure of the request containing the parameters of the communication is like this:
typedef struct i2c_req i2c_req_t;
struct i2c_req {
uint8_t addr; // I2C 7-bit Address
unsigned tx_len; // Length of tx data
unsigned rx_len; // Length of rx
unsigned tx_num; // Number of tx bytes sent
unsigned rx_num; // Number of rx bytes sent
uint8_t *tx_data; // Data for mater write/slave read
uint8_t *rx_data; // Data for master read/slave write
};
Is declared like so in the beginning of the file:
static i2c_req_t req;
and assigned this way in my_I2C_Init():
uint8_t rx[1] = {0};
uint8_t tx[1] = {12};
req.addr = 0xAA;
req.tx_data = tx;
req.tx_len = 1;
req.rx_data = rx;
req.rx_len = 1;
req.tx_num = 0;
req.rx_num = 0;
Many thanks for your help
I am receiving/reading data from a GPS module sent via USART3 to the STM32F091.
The data gets there just fine which I confirm by sending it to my PC COM3 port and feeding it to 'u-center' (GPS evaulation software).
My problem is that I want to evaluate the data myself in my C program, and for that purpose I feed it into a Ring Buffer, however, every character of the GPS signal is written multiple times to the buffer, instead of one by one.
For example
GGGGGGGPPPPPPPPSSSSSSSS instead of GPS
I am unsure what I'm doing wrong, maybe it's something really obvious I'm overlooking after staring at this code so long.
Here's the relevant code.
stm32f0xx_it.c
#include <main.h>
void USART3_8_IRQHandler(void)
{
if (USART_FLAG_RXNE != RESET)
{
uint16_t byte = 0;
/* Data reception */
/* Clear Overrun Error Flag, necessary when RXNE is used */
USART_GetITStatus(USART3, USART_IT_ORE);
/* Read from Receive Data Register and put into byte */
byte = USART_ReceiveData(USART3);
(*pRXD3).wr = ((*pRXD3).wr + 1) % (*pRXD3).max;
(*pRXD3).Buffer[(*pRXD3).wr] = byte;
/* Send Data to PC, and reset Transmission Complete Flag */
USART_GetITStatus(USART1, USART_IT_TC);
USART_SendData(USART1, byte);
return;
}
return;
}
uartGPS.h
....
struct GPSuart
{
BYTE Buffer[255];
WORD max;
WORD re;
WORD wr;
};
....
main.h
....
extern volatile BYTE B_ser_txd_3[255];
extern volatile BYTE B_ser_rxd_3[255];
extern volatile struct GPSuart TXD_uart_3;
extern volatile struct GPSuart RXD_uart_3;
extern volatile struct GPSuart *pRXD3;
extern volatile struct GPSuart *pTXD3;
....
Let me know if I should provide additional information.
This:
if (USART_FLAG_RXNE != RESET)
does not test a flag, that code is inspecting the flag constant itself, which is not what you meant.
You need more code, to access the UART's status register and check the flag:
if (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) != RESET)
Suppose we want to write at address say 0xc000, we can define a macro in C as:
#define LCDCW1_ADDR 0xc000
#define READ_LCDCW1() (*(volatile uint32_t *)LCDCW1_ADDR)
#define WRITE_LCDCW1(val) ((*(volatile uint32_t *)LCDCW1_ADDR) = (val))
My question is that when using any micro-controller, consider an example MSP430, P1OUT register address is 0x0021.
But when we use P1OUT=0xFFFF; // it assigns P1OUT a value 0xFFFF.
My question is how does it write to that address e.g. in this case 0x0021.
The IDE is IAR. I found in header msp430g2553.h below definition:
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
I suppose it is defining the address, but where are the other macros to write or read.
Could anyone please explain the flow that how P1OUT writes at that particular address location? Also do let me know what does u mean in 0x0021u ?
Thanks
So far the details I have found are :
in msp430g2553.h
#ifdef __IAR_SYSTEMS_ICC__
#include "in430.h"
#pragma language=extended
#define DEFC(name, address) __no_init volatile unsigned char name # address;
#define DEFW(name, address) __no_init volatile unsigned short name # address;
#define DEFXC volatile unsigned char
#define DEFXW volatile unsigned short
#endif /* __IAR_SYSTEMS_ICC__ */
#ifdef __IAR_SYSTEMS_ASM__
#define DEFC(name, address) sfrb name = address;
#define DEFW(name, address) sfrw name = address;
#endif /* __IAR_SYSTEMS_ASM__*/
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
The io430g2553.h says
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
Can some one explain what the above definition does? The details I found in MSP430 IAR C/C++ Compiler:
Example of using __write and __read
The code in the following examples use memory-mapped I/O to write to an LCD
display:
__no_init volatile unsigned char LCD_IO # address;
size_t __write(int Handle, const unsigned char * Buf,
size_t Bufsize)
{
size_t nChars = 0;
/* Check for stdout and stderr
(only necessary if file descriptors are enabled.) */
if (Handle != 1 && Handle != 2)
{
return -1;
}
for (/*Empty */; Bufsize > 0; --Bufsize)
{
LCD_IO = * Buf++;
++nChars;
}
return nChars;
}
The code in the following example uses memory-mapped I/O to read from a keyboard:
__no_init volatile unsigned char KB_IO # 0xD2;
size_t __read(int Handle, unsigned char *Buf, size_t BufSize)
{
size_t nChars = 0;
/* Check for stdin
(only necessary if FILE descriptors are enabled) */
if (Handle != 0)
{
return -1;
}
for (/*Empty*/; BufSize > 0; --BufSize)
{
unsigned char c = KB_IO;
if (c == 0)
break;
*Buf++ = c;
++nChars;
}
return nChars;
}
Does any one know?
This is "how does the compiler generate the code from what I've written", and only the compiler writers will actually be able to answer that for you.
Clearly, there are several non standard C components in the code above __no_init, the use of #, etc. In my reading of this, it tells the compiler that "this is a HW port, that provides an unsigned char, and it's address is 0xd2". The compiler will produce the right kind of instructions to read and write such a port - exactly how that works depends on the compiler, the processor that the compiler is producing code for, etc.
The P10out structure defines bitfields, which is part of the C standard. Google is your friend here.
Indirection operator (unary *) returns l-value equivalent to the value at pointer address.
#define LCDCW1_ADDR 0xc000
void f()
{
uint32_t a = *(volatile uint32_t *)LCDCW1_ADDR; //reading from LCDCW1_ADDR
*(volatile uint32_t *)LCDCW1_ADDR = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
Basically, compiler is smart enough to see, that a = *addr; expression means "read value from addr address and put it to a. At the same time *addr = 0xffff will be interpreted like "put 0xffff to addr address"
In your case you can use your READ_LCDCW1() macro both on left and right hand side of assignment operator. There is no need for separate WRITE_LCDCW1(val) macro. We can rewrite the previous code as:
#define LCDCW1_ADDR 0xc000
#define LCDCW1 (*(volatile uint32_t *)LCDCW1_ADDR)
void g()
{
uint32_t a = LCDCW1; //reading from LCDCW1_ADDR
LCDCW1 = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
P1OUT macro from IAR is most probably defined the same way as LCDCW1 above (if you follow the DEFC() definition you will eventually find something like it).
My question is that when using any micro-controller, consider an
example MSP430
You're not using any micro-controller, you are using an MSP430. It has memory-mapped IO (which is really nice to use for us programmers). The memory mapping will vary based on device. The answers to any of the address related questions lie within your specific device's User's Guide. TI makes very good User Guide's. Find the one for your specific device and read it thoroughly.
My question is how does it write to that address e.g. in this case
0x0021. The IDE is IAR.
Compiler glue code. Your compiler vendor will supply you with the necessary headers, macros and functions to write to your device addresses. Use the compiler vendor's code unless you can absolutely prove that it is not working for your case (with IAR I would assume that 99.9% it works, you get what you pay for. Possibly with a brand new device there are bugs in the implementation, but probably not unless you can prove it).
Also do let me know what does u mean in 0x0021u ?
From what you've posted, that is the base address for port 1. It looks like you have 8 pins on port 1 you can control.
#pragma language=extended
From this point on you must assume that there are all sorts of "magical" (aka non-standard C) things that will be happening. You can infer what you think the compiler is doing (and for the most part it is reasonably clear), however this is implementation defined, meaning only IAR compiler supports what will happen next. Look at the compiler docs for specific commands and meanings. Most notably the __no_init and the # symbol are non-standard. The __no_init will not initialize the variable at C startup (i.e. before main() runs). The # looks like an absolute address instruction that will be given to the linker (I may be wrong here).
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
This defines a way to get at specific bits of the byte for port 1. This lets you manipulate the IO pins. Some would say OMG bitfields are portable, the are implementation defined! Yes, they are right, but IAR is the implementor, so in this case just trust them to do the right thing.
Final note, you probably just want to use the IAR macros as defined. You paid a lot of money for them (unless you are using the free kickstart edition). You can concentrate on writing your app and not manipulating bits this way. IAR does do a good job of standardizing their names, so you can also use the same code (or very similar) on related parts. If you switch to a different compiler all this goes out the window and you'll have to do it the way of the new compiler. Good and bad points to this approach, probably no "right" answer.
The connection is as follows An infrared sensor circuit which yields 0 or 5v depending on closed or open circuit output line to port 2_0 pin of microcontroller 8051 philips.Problem is when i do this the circuit value are overridden by the current value on port 2_0 led always goes on.Here is my code(in keil c) i guess i have not configured P 2_0 as input properly
void MSDelay(unsigned int);
sbit led=P1^0;
void main()
{
unsigned int var;
P2=0xFF;
TMOD=0x20;
TH1=0xFD;
SCON =0x50;
TR1=1;
while(1)
{
var=P2^0;
if(var==0)
{
led=1;
SBUF='0';
while(TI==0);
TI=0;
MSDelay(250);
}
else
{
led=0;
SBUF='9';
while(TI==0);
TI=0;
MSDelay(100);
}
}
}
EDIT : I was facing a problem since the 8086 processor i was using had a fault in it. Would recommend anyone trying this to get a few spares when programming.
jschmier has a good point. Also the port may not be configured correctly, or is there something in the circuit that is causing the led to toggle off and on very quickly so it looks like it is on all the time.
You typically use the sbit data type for P2_0 to define a bit within a special function register (SFR).
From C51: READING FROM AN INPUT PORT (modified)
sfr P2 = 0xA0;
sbit P2_0 = P2^0;
...
P2_0 = 1; /* set port for input */
var = P2_0; /* read P2_0 into var */
It is important to note that sbit variables may not be declared inside a function. They must be declared outside of the function body.
Another option may be to read all 8 pins of P2 and then mask off the unwanted bits.
char var; /* define 8 bit variable */
P2 = 0xFF; /* set P2 for input */
var = P2; /* read P2 into var */
var &= 0x01; /* mask off unwanted bits */
Rather than read P2 or the P2_0 pin into an unsigned int (16 bits), you could use a char (8 bits) or single bit to save on memory.
char var;
...
var = P2;
or
bit var;
...
var = P2_0;
Another option may be to make the char bit-addressable.
char bdata var; /* bit-addressable char */
sbit var_0 = var^0; /* bit 0 of var */
...
var = P2; /* read P2 into var */
if(var_0 == 0) /* test var_0 (bit 0 of var char) */
{
...
}
You can find additional useful information in the Keil Cx51 Compiler User's Guide and related links.
Note: Most of my 8051 experience is in assembly. The C examples above may not be 100% correct.
Thank you so much... my coding works
And I learn how to define input port and read the data
#include<reg51.h>
#define opp P1
#define ipp P0
sbit op =P1^0;
sbit ip =P0^0;
main()
{
unsigned int value;
P0=0xFF;
value=P0;
value &=0x01;
if(value==0)
{
P1=0x01;
}
else
{
P1=0x00;
}
}