Structure pointer initialized with a value behaves like enum - c++

I was reading an article regarding bare bones programming of ARM processor when I came across the following code
struct systick {
volatile uint32_t CTRL, LOAD, VAL, CALIB;
};
#define SYSTICK ((struct systick *) 0xe000e010)
#define BIT(x) (1UL << (x))
static inline void systick_init(uint32_t ticks) {
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
SYSTICK->LOAD = ticks - 1;
SYSTICK->VAL = 0;
SYSTICK->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
}
I am not able to understand how does initializing a pointer to a structure initialize variables inside a structure? Does the ARM compiler treat it as an enum?
Thanks!

It's very likely a memory-mapped device. So, when you write to structure members, you're essentially manipulating the hardware, just as with port output (but in this case, memory-mapped). So you're essentially writing to a hardware that's available on addresses 0xe000e010, 0xe000e014, 0xe000e018, 0xe000e01c respectively for CTRL, LOAD, VAL, CALIB. Then you set particular bits manually.

Related

Using custom data type in separate library

I am trying to tie together a few different libraries for a project I'm working on. The code is for a Teensy 4.1 in VS Code and PlatformIO
I am trying to use lvgl https://lvgl.io/ (graphics library) and ILI9341_t3n LCD libraries https://github.com/KurtE/ILI9341_t3n.
The ILI9341_t3n library has functions that use DMA to asynchronously update the display. I would like to use it as my display driver.
The ILI9341_t3n library uses a framebuffer and the pointer is pointing to a uint16_t.
However, the lvgl library does things a bit differently. It uses a _lv_disp_draw_buf_t struct to hold several more variables, like fb size, which buffer to use (if double buffer) and other status indicators.
typedef struct _lv_disp_draw_buf_t {
void * buf1; /**< First display buffer.*/
void * buf2; /**< Second display buffer.*/
/*Internal, used by the library*/
void * buf_act;
uint32_t size; /*In pixel count*/
/*1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/
volatile int flushing;
/*1: It was the last chunk to flush. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/
volatile int flushing_last;
volatile uint32_t last_area : 1; /*1: the last area is being rendered*/
volatile uint32_t last_part : 1; /*1: the last part of the current area is being rendered*/
} lv_disp_draw_buf_t;
The code to create and initialize a buffer is as follows.
static _lv_disp_draw_buf_t draw_buf;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A screen sized buffer*/
static lv_color_t buf_2[MY_DISP_HOR_RES * 10]; /*Another screen sized buffer*/
lv_disp_draw_buf_init(&draw_buf, buf_1, buf_2, MY_DISP_HOR_RES * 10); /*Initialize
The init code is:
void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t
size_in_px_cnt)
{
lv_memset_00(draw_buf, sizeof(uint16_t));
draw_buf->buf1 = buf1;
draw_buf->buf2 = buf2;
draw_buf->buf_act = draw_buf->buf1;
draw_buf->size = size_in_px_cnt;
}
The ILI9341_t3n code for initializing the frame buffer is much more simple.
void ILI9341_t3n::setFrameBuffer(uint16_t *frame_buffer) {
#ifdef ENABLE_ILI9341_FRAMEBUFFER
_pfbtft = frame_buffer;
_dma_state &= ~ILI9341_DMA_INIT; // clear that we init the dma chain as our
// buffer has changed...
#endif
}
I would like to create a framebuffer like the lvgl library recommends, and then pass it into this function. I can modify the code so that the LCD library can do something like:
_pfbtft = draw_buf->buf1;
//or//
_pfbtft = draw_buf->buf2;
That way, I can use lvgl to update the framebuffer, and use the ILI9341 library just for handling the DMA transactions.
The problem is I don't know how to incorporate the _lv_disp_draw_buf_t data type into the ILI9341 library. I tried changing the uint16_t to _lv_disp_draw_buf_t just to see what would happen and it says it's an undefined variable type.
Is this a somewhat trivial task or will it require rewriting a lot of code?
Or maybe I dont need to incorporate it. If I call:
tft.setFrameBuffer(&frame_buffer);
Is there a way I could access the framebuffer pointer contained in the _lv_disp_draw_buf_t data type and pass it instead?
If it's not a simple answer, please advise some topics that I should study so that I can learn how to do this.
It's possible I'm going about this all wrong, so constructive criticism is appreciated.
I did several google searches to see if this has been answered before, but my search terms are limited by my knowledge of the terminology, so if it has I apologize.

C++ compilation error: request for member ‘c_cflag' in something not a structure or union

I am trying to compile cp210x USB-UART driver on Debian 7 and getting the following error (when make command):
/var/distr/sillabs/Linux_3.x.x_VCP_Driver_Source/cp210x.c:589:17: error: request for member ‘c_cflag’ in something not a structure or union
Here is a fragment of code, line 589 (starts with &tty->), cp210x.c:
static void cp210x_get_termios(struct tty_struct *tty,
struct usb_serial_port *port)
{
unsigned int baud;
if (tty) {
cp210x_get_termios_port(tty->driver_data,
&tty->termios.c_cflag, &baud);
tty_encode_baud_rate(tty, baud, baud);
} else {
unsigned int cflag;
cflag = 0;
cp210x_get_termios_port(port, &cflag, &baud);
}
}
I think something is wrong with the &tty->termios.c_cflag construction. Please help how to fix it?
Thank you!
It means that in your definition of tty_struct, termios is a structure pointer, not a structure. You need to change the expression
&tty->termios.c_cflag
to
&tty->termios->c_cflag
The definition of tty_struct changed between versions 2.x and 3.x of the Linux kernel.
The driver you're building expects it to contain:
struct ktermios termios, termios_locked;
from 3.x, but you are using the includes from 2.x:
struct ktermios *termios, *termios_locked;
You can either reconsider the kernel you're using to better meet the driver's requirements, or you can hack the driver's code yourself:
- &tty->termios.c_cflag
+ &tty->termios->c_cflag
I would also suggest talking to the driver developer about this, if the requirements are unclear.
a tty_struct contain, among other thing:
// from tty.h
struct tty_struct {
int magic;
// some cut
struct ktermios termios, termios_locked;
// more cut
};
a ktermios in turn, is defined like:
// from termbits.h
struct ktermios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
};
and finally, a tcflag_t is:
// also from termbits.h
typedef unsigned int tcflag_t;
so, in conclusion, it should work.
What could muck up that? My first guess would be a macro.
Prime suspect would be that you have a termios macro.
If not that, don't look for the error at line where its reported, it's probably a side-effect of something else.
For example, do you have old headers that the compiler might find instead of those you want? If you are trying to compile a driver for v3 with headers from v2 it wont work.

Passing array of stuct to kernel results in segfault on write?

Maybe I missed something from the tutorials because this is driving me nuts.
What I'm trying to accomplish: I want to create an array of structs for the OpenCL device to use as a work area. The host doesn't need to see it or interact with it in any way, it's just meant as a "scratch" space for the kernel to work within.
Here's what I have:
Declaration of struct inside header file accessible by both the main program and the OpenCL kernel:
typedef struct {
uint64_t a;
uint32_t b;
} result_list;
Initializing the scratch space buffer "outputBuffer" to hold MAX_SIZE elements:
cl_mem outputBuffer;
outputBuffer = clCreateBuffer(this->context,
CL_MEM_READ_WRITE,
sizeof(result_list) * MAX_SIZE,
NULL,
&status);
I never call clEnqueueWriteBuffer because the host doesn't care what the memory is. It's simply meant to be a working space for the kernel. I leave it as uninitialized but allocated.
Setting it as an argument for the kernel to use:
status = clSetKernelArg(myKernel,
1,
sizeof(cl_mem),
&this->outputBuffer);
The kernel (simplified to remove non-issue sections):
__kernel void kernelFunc(__global const uint32_t *input, __global result_list *outputBuffer) {
if (get_global_id(0) >= MAX_SIZE) { return; }
// Make a few local variables and play with them
outputBuffer[0].a = 1234; // Memory access violation here
// Code never reaches here
}
What am I doing wrong?
I installed CodeXL from AMD and it doesn't help much with debugging issues like these. The most it gives me is "The thread tried to read from or write to a virtual address to which it does not have access."
edit: It seems like it really doesn't like typedefs. Instead of using a struct, I simplified it to typedef uint64_t result_list and it refused to compile, saying "a value of type 'ulong' cannot be assigned to an entity of type 'result_list'", even though result_list -> uint64_t -> unsigned long.
Your problem is that you cannot put in a single header both definitions for HOST and DEVICE.
You have to separate them like this:
//HOST header
struct mystruct{
cl_ulong a;
cl_uint b;
};
//DEVICE header
typedef struct{
ulong a;
uint b;
} mystruct;
Notice that I also changed the datatype to the standar OpenCL datatypes. You should use those instead for compatibility.

Read-only memory-mapped registers defined with `volatile const` in C but only `volatile` in C++

While working on an embedded systems project using an Atmel SAM3X8E, I noticed the following bit of code in some of the CMSIS header files.
#ifndef __cplusplus
typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#else
typedef volatile uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#endif
Why does the typedef for C++ not include const? I saw somewhere a mention that C++ does not store integer const variables in runtime memory, which if true would mean the const would need to be removed because of how microcontroller registers are memory-mapped, but I can't seem to find anything else saying that C++ does that (though my search was admittedly pretty brief). Not having much experience with C++, I also thought it might be that C++ doesn't allow const struct members, as those typedefs are mostly used in struct typedefs for collections of registers, but that doesn't seem to be the case either.
If you declare with const, C++ standard will obligate you to initialize the contents of the variable. In the case of micro-controller register, you do not want to do that.
Because no RoReg object is ever instantiated, there is no good reason to omit the const qualifier in the typedef.
Every use of RoReg is in either a macro that defines a pointer to the type...
#define REG_WDT_SR (*(RoReg*)0x400E1A58U) /**< \brief (WDT) Status Register */
...or a struct declaration that is accessed using a similar macro.
typedef struct {
WoReg WDT_CR; /**< \brief (Wdt Offset: 0x00) Control Register */
RwReg WDT_MR; /**< \brief (Wdt Offset: 0x04) Mode Register */
RoReg WDT_SR; /**< \brief (Wdt Offset: 0x08) Status Register */
} Wdt;
#define WDT ((Wdt *)0x400E1A50U) /**< \brief (WDT) Base Address */
Even with the const qualifier, the code should behave the same in both C and C++.
Perhaps the author misinterpreted the standard. To guarantee that a C++ struct has the same layout as in C, it requires that the class "has the same access control (Clause 11) for all non-static data members." The author may have mistaken const and volatile for access control specifiers. If they were, then you would want all the struct members to have the same cv-qualifiers in order to ensure compatibility between the C and C++ (and hardware) layouts. But it's public, protected, and private that define access control.
As mentioned by #fanl, const does indeed change the default linkage of globals in C++, and does prevent defining a variable without initialization.
But there are better ways to get external linkage than removing const. The usage of reserved arrays in the header file Chris linked is also very fragile. I would say this code leaves a lot of room for improvement -- don't emulate it.
And furthermore these variables don't get defined (that would cause the compiler and linker to select an address), they are always accessed via pointers, with the address fixed according to the memory map.
For headers intended purely for use by C++, this is how I do it (memory map matching a TI Stellaris chip).
Looks complicated, but the optimizing compiler reduces it down to a single instruction per access. And the address offsets are coded in, not dependent on the order and padding of fields inside a structure, so it's much less fragile and easier to verify against the datasheet.
template<uintptr_t extent>
struct memory_mapped_peripheral
{
char data[extent];
volatile uint32_t* offset( uintptr_t off ) { return reinterpret_cast<volatile uint32_t*>(data+off); }
volatile const uint32_t* offset( uintptr_t off ) const { return reinterpret_cast<volatile const uint32_t*>(data+off); }
};
struct LM3S_SYSTICK : private memory_mapped_peripheral<0x1000>
{
volatile uint32_t& CTRL (void) { return offset(0x010)[0]; }
volatile uint32_t& RELOAD (void) { return offset(0x014)[0]; }
volatile uint32_t& CURRENT(void) { return offset(0x018)[0]; }
}* const SYSTICK = reinterpret_cast<LM3S_SYSTICK*>(0xE000E000);
struct LM3S_NVIC : private memory_mapped_peripheral<0x1000>
{
volatile uint32_t& EN (uintptr_t i) { return offset(0x100)[i]; }
volatile uint32_t& DIS (uintptr_t i) { return offset(0x180)[i]; }
volatile uint32_t& PEND (uintptr_t i) { return offset(0x200)[i]; }
volatile uint32_t& UNPEND(uintptr_t i) { return offset(0x280)[i]; }
volatile const uint32_t& ACTIVE(uintptr_t i) const { return offset(0x300)[i]; }
volatile uint32_t& PRI (uintptr_t i) { return offset(0x400)[i]; }
volatile uint32_t& SWTRIG(void) { return offset(0xF00)[0]; }
}* const NVIC = reinterpret_cast<LM3S_NVIC*>(0xE000E000);

Passing a Port as a variable - AVR

Is it possible to use an AVR port as a variable which can be passed around?
For example
LED myLed(PORTA,7); //myLED hooked to PORTA, Pin 7
I would like to make LED be able to take any PORT / Pin combination, so I would rather not hard code it in.
Note that the PORTs are defined as:
#define PINA _SFR_IO8(0x00)
#define DDRA _SFR_IO8(0x01)
#define PORTA _SFR_IO8(0x02)
PORTA symbol resolves to (*(volatile uint8_t *)((0x02) + 0x20))
I believe this would allow me to do something like the following, but I am unsure whether I would need the volatile keyword or not, nor whether it will actually work as expected
class LED{
public:
LED(volatile uint8_t* port, uint8_t pin);
{
Port=port;
Pin=pin;
}
void write(bool val)
{
if(val) (*Port) |= 1 << Pin;
else (*Port) &= ~(1 << Pin);
}
private:
uint8_t Pin
volatile uint8_t* Port;
}
Finally, is there a way to set Port / Pin as an Output from the LED Constructor?
This would involve finding the relative DDR# register for the Given PORT#.
Can I assume &DDR# will always be &PORT#-1?
The register macros are basically pointers to the memory location, where the appropriate register resides, so yes, you can use uint8_t volatile *. However, the compiler will not generate the most efficient code this way -- it will use indirect addressing instead of direct writes.
This is what I do instead, using avrlib.
#include <avrlib/porta.hpp>
#include <avrlib/pin.hpp>
using namespace avrlib;
typedef pin<porta, 4> led_pin;
Then you can use the led_pin typedef, e.g.
led_pin::set();
This is how I did it, im not very experienced in AVR,
#include <avr/io.h>
void LED(volatile uint8_t* port, uint8_t pin)
{
// First set DDRx ; DDRx on ATmega32 is one address below port address
*(port -1) |= (1<< pin);
// Now set the pin high
*port |= (1<< pin);
}
int main(void)
{
LED(&PORTB,1);
LED(&PORTC,2);
LED(&PORTD,3);
while (1)
{
}
}
Ports are nothing more than I/O addresses, so all you have to do is pass the address of the I/O port to you LED constructor:
LED *light = new LED(&PORTA, 4);
Why does this work? PORTA resolves, as you already mentioned, to the dereferencing of a pointer:
(*(volatile uint8_t *)((0x02) + 0x20))
So adding an address of operator in front creates
&(*(volatile uint8_t *)((0x02) + 0x20))
which can be simplified to
(volatile uint8_t *)((0x02) + 0x20)