I have a number of arrays all of different sizes that I have stored in flash memory.
I can access single array entries with
byte j = pgm_read_byte(&(array[x]));
What I want to do is to pass the array from the flash memory as an argument to a function. I have tried giving a pointer to the array, as an argument but this gives a compilation error:
void callPGM2(byte arr_size, byte *arr) {
..
..
}
ptr2 = &pgm_read_byte(&(array_1[0]));
callPGM2(5, &ptr2);
Can full arrays be passed from flash memory as function arguments?
There's no way to directly pass a pointer to PROGMEM variables, because of the AVR's Harvard architecture with 2 address spaces that C has no way to straightforwardly express - You need to temporarily copy the memory to RAM using memcpy_P, for example.
And you want to learn about the functions provided in the pgmspace library. It holds equivalents to a number of C functions like strcmp, that allow you to work with a constant argument in program space.
To copy a string from flash memory to RAM
#include<avr/pgmspace.h>
const byte Update_1[5] PROGMEM = {0x01, 0xB2, 0x02, 0xFF, 0xFF};
byte buffer2[5];
setup {
memcpy_P (buffer2, &(Update_1),5);
}
Related
I'm writing an application for a PIC18F45K80 microcontroller. I would like to retrieve bytes from the eight RXB1D registers. According to the datasheet, "Each receive buffer has an array of registers." Also, studying the defines reveals that all 8 registers have consecutive memory addresses, just like an array.
What is the correct syntax for looping through these registers?
I've tried for (i = 0; i < len; i++) databuf[i] = RXB1D0[i];, but the compiler returns error: subscripted value is not an array, pointer, or vector, and points to the RXB1D0 identifier.
I would discourage you from doing it this way as PICs use Hardware architecture and memory access via a pointer in some areas might not work as it requires special assembly instructions. They are only 8 so I would do it this way:
#define GETREG(b, i) (b)[i] = RXB1D ## i
#define GETREGS(b) do {GETREG(b,0);GETREG(b,1);GETREG(b,2);GETREG(b,3);\
GETREG(b,4);GETREG(b,5);GETREG(b,6);GETREG(b,7);}while(0)
and usage:
void foo()
{
char databuff[8];
GETREGS(databuff);
}
Every read will compile to two assembly instructions. Even if you find the way of looping using pointers it will result in much more instructions.
I'm writing an embedded program, which is divided in two parts: bootloader and app. (I'm targeting the STM32 and doing my development in C using the Eclipse IDE.)
I'm using a display, so I wrote some functions and 3 different fonts.
The idea is to use a sector of the microcontroller and share it.
The font area is defined with a linker (ld) script like so:
.mySegment start_of_FONT_segm : {KEEP(*(.Courier_New_Bold_20_Section))}
.mySegment1 0x8011298 : {KEEP(*(.Terminal6x8_Section))}
Then, I use an array to write in:
const unsigned char __attribute__((section (".Terminal6x8_Section"))) Terminal6x8[] = {
0x00,
0x00,
...
But how do I read it from another program (in this case, the application)?
I tried with:
unsigned char *Terminal6x8 = (volatile unsigned char*)0x08011298;
but the compiler puts the Terminal6x8 into RAM.
I'll be glad to share some functions also, but I don't know how to declare those in ld and C syntax, either.
The following line of code:
unsigned char *Terminal6x8 = (volatile unsigned char*)0x08011298;
is bad for many different reasons:
It uses a fixed (hard-coded) address, which is not very good.
It declares the data as volatile, which makes no sense in this context.
It does not declare the data as constant.
If you want the pointer to be also placed in the flash memory, you should write:
const unsigned char * const Terminal6x8 = (const unsigned char * const) 0x08011298;
I'll be glad to share some functions also, but don't know how to declare in ld and C syntax too.
The proper way to do it is to declare a vector table (i.e., a table of pointers) containing the pointers to the data and the functions you want to share between the flash segments.
Indeed the pointer *Terminal6x8 is put into RAM. If you want the pointer stored in flash, declare it const.
Although, the data pointed to by *Terminal6x8 is stored in flash at address 0x08011298 as you want. No matter where the pointer is stored.
For a display driver in an arm project, I want to access the buffer as 2D array to access it like this:
e.g. display_buffer[2][113]=0xff;
To write the buffer out to the display via I2C I want to write the whole buffer out, but need to prepend it with 0x40.
io_write(I2C_0_io, (uint8_t *)buf, 513); //where buf should be 0x40,content, of, display_buffer,...
Is there a way to declare display_buffer[4][128] so that it has one byte before it and a pointer that points to it?
I tried
uint8_t *_display_buffer = (uint8_t*)513;
uint8_t *display_buffer[4][128]=_display_buffer+1;
but of course the compiler thought that this was not a good idea ('invalid initializer')
You need to define _display_buffer as an array large enough to hold your 2D array plus 1 byte, and display_buffer as a pointer to an array (which you can index as a 2D array) instead of a 2D array:
uint8_t _display_buffer[513] = { 0x40 };
uint8_t (*display_buffer)[128]=(uint8_t (*)[128])(_display_buffer+1);
I'm trying to emulate a system that needs to copy data to a peripheral, bare metal, no OS.
The convention states that the copy function is a C-function which takes as the address of the peripheral an 8-bit address that is written to a certain register. The peripheral uses that internally. However, I'm simulating the thing in C and to test the full functionality I am doing something like the following MWE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[]){
//stack-array to copy
char array[4] = {3,32,-12,99};
//naive emulation of the peripheral memory space
char peripheral_array[4];
//herein lies the address send as a value
char address_reg = (char*)(peripheral_array);
//assume this is the peripheral side
//set ptr to the address of the peripheral_array
char *ptr = (char*) address_reg;
memcpy((void*)ptr,array,sizeof(char)*4);
return EXIT_SUCCESS;
}
I get segmentation fault.
What's the issue at hand here?
How can I store the pointer of array as a value, send it, recast it successfully as the address to an array and perform the memcpy?
You want to emulate something with a 8-bit address space in an environment with a 32-bit or 64-bit address space, and thus you have some difficulties, because it doesn't convert trivially. Specifically, this line char address_reg = (char*)(peripheral_array) cast a wide pointer to a 8-bit value, and lose most of the pointer, which means you won't be able to convert back.
The solution is to push further your simulation and emulate your destination 8-bit address space :
Typedef a 8-bit pointer (cleaner) : typedef uint8_t ptr8;
Declare your 8-bit destination address space : uint8_t my_destination_memory[256]
Define you own memcpy to copy to this address space : void my_memcpy( ptr8 addr_dest, const void * src, int len ) {
memcpy( my_destination_memory + addr_dest, src, len );
}
This way you can pass around your 8-bit pointer of type ptr8 (or whatever you name it) and copy to it without problem.
Note that I assumed that your source address space is not of importance, buti f it is you can also emulate it. You should be able to emulate 16-bit or even 24-bit address space in the same way (You can use the native pointers if you need 32-bit).
why storing it into char? the variable that can hold an address to a char is a char* - On Both machines - your PC and your embedded MCU!
On your MCU sizeof(char*) may be 1 or 2, and on your PC it may be 4 or 8;
If you want to write platform compatible code, use a char*.
If you want to go a few steps further to simulating the machines address space then you have to provide own implementations of the standard-lib functions. So that they interpret addresses in machines address space as indices to some some memory array that you defined.
However the better approach is mostly to provide some Hardware Abstraction Layer (HAL) that encapsulates system specific tasks, rather than using machine specifica in your business logic.
First of all, please note that storing integer values in the char type is dangerous, since it is a type with implementation-defined signedness. It should never be used for anything but strings.
Instead, always use either int8_t (signed) or uint8_t (unsigned).
The cause of the problem is that a char (or an int8_t for that matter) is not large enough to hold an address.
There is however the uintptr_t in stdint.h which is guaranteed to be large enough to contain an address.
Simply replace
char address_reg = (char*)(peripheral_array);
with
uintptr_t address_reg = (uintptr_t)peripheral_array;
I'm a complete novice in everything except maybe breathing, so sorry if I'm not being clear, but here goes:
I have a function in C which writes bytes to a circuit via an I2C bus, and in the header file it looks like this:
BOOL WINAPI JidaI2CWrite(HJIDA hJida, DWORD dwType, BYTE bAddr, LPBYTE pBytes, DWORD dwLen);
hJida: Board handle.
dwType: Zero-based number of the I2C
bus.
bAddr: Address of the device on the
I2C bus, the full 8 bits as it is
written to the bus.
pBytes: Pointer to location that
contains the bytes.
dwLen: Number of bytes to write.
If I wanted to write just one byte to a circuit with the address 0x98, I would do something like this:
unsigned char writing[1];
writing[0]=0x10;
unsigned char *pointer;
pointer = &writing[0];
JidaI2CWrite(hJida,0,0x98,pointer,1);
which seems to work, but if I wanted to write two bytes, say 0x10FF, it doesn't. So how do I make a pointer that points to two bytes instead of just one?
Thanks
You want something like this:
unsigned char writing[2];
writing[0] = 0x01;
writing[1] = 0x02;
JidaI2CWrite(hJida, 0, 0x98, writing, 2);
Notice that an array in C can be usually be used just like a pointer. The variable writing can be thought of as just a pointer to a chunk of memory that in this case has a size of 2 bytes. Creating another pointer to point to that location is redundant (in this case).
Note you could make it point to any number of bytes:
unsigned char writing[12];
//fill the array with data
JidaI2CWrite(hJida, 0, 0x98, writing, 12);
Try this...
//A buffer containing the bytes to be written
unsigned char writeBuffer[] = {0x10, 0xFF};
//writeBuffer itself points to the start of the write buffer
//you dont need an extra pointer variable
//Indicate the size of the buffer in the call to the function
//pointers do not carry array size information with them (in C/C++)
JidaI2CWrite(hJida,0,0x98,writeBuffer,2);
or better yet
unsigned char writeBuffer[] = {0x10, 0xFF};
JidaI2CWrite(hJida,0,0x98,writeBuffer
,sizeof(writeBuffer)/sizeof(unsigned char));
Note: sizeof(writeBuffer)/sizeof(writeBuffer[0]) automatically calculates the size of the array in bytes for you
It appears as though the dwLen parameter is the number of bytes to write. So:
unsigned char writing[2];
writing[0] = 0x10;
writing[1] = 0xff;
JidaI2CWrite(hJida, 0, 0x98, writing, 2);
Note that your use of pointer pointing to writing[1] probably shouldn't work as written, because that sets pointer to point to the byte after the byte you really want to write. I'm suspecting this is a typo, but if not you may wish to review your existing code before proceeding.
writing is already the pointer that you want.
Get rid of pointer.
The final parameter to JidaI2CWrite is the number of bytes you want to to write.
The pointer pBytes points to the start of the block you want to write.
I see 2 choices:
1) write them separately:
writing[0] = 0x10;
writing[1] = 0xFF;
2) check if short on your system is 2Bytes and use a short.
probably as ((short*)writing)[0] = 0x10FF;
Also, you need to declaire writing is char writing[2];
and then, as others have said, write the 2 bytes...