memcpy from array to area of memory - c

I am working on a small embedded device, where to draw graphics to the screen, you need to write bytes to an area of vram and then flush it to the display.
If I have an image of the same size as the screen, in standard c array form, would the correct way to copy the image be:
memcpy(vram_base, image, LCD_HEIGHT_PX*LCD_WIDTH_PX*3) //3 bytes for 24-bit colour
where vram_base is the non-changing start point of the area that can be flushed to the lcd
and image is of the form
char img[] = {0x00, 0xd6, 0x3a, ...}
If that's not the right, what would be the right way in c?

Related

Why does this code clear the screen on the SparkFun 16x2 SerLCD

I have been playing around with SparkFun 16x2 SerLCD LCD from SparkFun and controlling it via the Tiva C EK-TM4C123GXL board. I have managed to connect the LCD via SPI communication and written code to display strings on the board. However I was having trouble writing code that would clear the screen for me until I came across this code online:
#include <stdint.h>
#include <stdlib.h>
#include "inc/tm4c123gh6pm.h"
void spi_master_ini(void){ //Setup SPI
SYSCTL_RCGCSSI_R|=(1<<2);
//SYSCTL_RCGCGPIO_R |=(1<<1);
SYSCTL_RCGC2_R |=(1<<1);
GPIO_PORTB_AFSEL_R|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
GPIO_PORTB_PCTL_R=0x22220000;
GPIO_PORTB_DEN_R|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
GPIO_PORTB_PUR_R|=(1<<4)|(1<<5)|(1<<6)|(1<<7);
SSI2_CR1_R=0;
SSI2_CC_R=0;
SSI2_CR1_R=64;
SSI2_CR0_R=0x7;
SSI2_CR1_R|=(1<<1);
}
void send_byte(char data){
SSI2_DR_R=data;
while((SSI2_SR_R&(1<<0))==0);
}
void send_str(char *buffer){
while(*buffer!=0){
send_byte(*buffer);
buffer++;
}
}
int main(){
spi_master_ini();
SSI2_DR_R=0x7C; //Put into setting mode.
SSI2_DR_R=0x2D; //Clear screen, move cursor to home position.
send_str("Testing");
}
Specifically the 2 lines of code that are puzzling me:
SSI2_DR_R=0x7C; //Put into setting mode.
SSI2_DR_R=0x2D; //Clear screen, move cursor to home position.
After reading through the HD44780U datasheet I wasn't able to see how sending those HEX values to the data lines would do anything other than print "|" and "-" to the LCD. However, to my surprise when I ran the code it works and clears my LCD screen.
The data sheet for the HD44780U is irrelevant - you are not talking directly to the display controller. On the SparkFun 16x2 SerLCD, the SPI communication is with the ATmega328P which in turn communicates with the display controller.
This simplifies the interface to the display, since you only need an SPI or I2C link and do not need a 4/8 bit data bus and additional control lines required by the display controller.
The software running on the ATMega328P interprets and translates commands independently of the display controller. The source code at https://github.com/sparkfun/OpenLCD applies.
settings.h has:
#define SPECIAL_SETTING '|' //124, 0x7C, the pipe character: The command to do special settings: baud, lines, width, backlight, splash, etc
Then in OpenLCD.ino void updateDisplay() there is:
//Check to see if the incoming byte is special
if (incoming == SPECIAL_SETTING) //SPECIAL_SETTING is 127
{
currentMode = MODE_SETTING;
}
...
note the comment is erroneous, it is 124 not 127 (perhaps says something about the quality of this code).
Then later:
else if (currentMode == MODE_SETTING)
{
currentMode = MODE_NORMAL; //In general, return to normal mode
...
//Clear screen and buffer
else if (incoming == 45) //- character
{
SerLCD.clear();
SerLCD.setCursor(0, 0);
clearFrameBuffer(); //Get rid of all characters in our buffer
}
...
Then clearFrameBuffer() simply fills the buffer with spaces rather then using the HD44780 "Clear Display" instruction:
//Flushes all characters from the frame buffer
void clearFrameBuffer()
{
//Clear the frame buffer
characterCount = 0;
for (byte x = 0 ; x < (settingLCDwidth * settingLCDlines) ; x++)
currentFrame[x] = ' ';
}
Much of the documentaton is for Arduino, but the command table at https://learn.sparkfun.com/tutorials/avr-based-serial-enabled-lcds-hookup-guide/firmware-overview is valid regardless. It is interms of characters rather then integer codes so has:
...
...
And many more commands you might find useful.

Is there any way I could avoid using the array in PROGMEM in Arduino or modify it?

I am using the SSD1306 OLED with Arduino. I am trying to send the Bitmap data via HC-05 Bluetooth module, so I can display the Bitmap image on the OLED.
The problem I'm facing is :
const uint8_t frame1[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff,...}
The above frame1[] array of preexisting Bitmap is of const type and gets stored in PROGMEM (has to be of const type) , and thus the array cannot be modified. Is there any other way I could display the received data or even, modify the frame1[] array to display the bitmap instantly as I get the bitmap data over Bluetooth?
PS : I'm using the U8g library for display
How about something like this:
uint8_t frame1[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,...};
You don't need to save the array in your arduinos PROGMEM,
you can also save it as a regular array.
That may only be a problem if your arduinos ram is too low,
so that the frame can only fit into PROGMEM - just try it

f3discovery: trying to use an lcd screen 1602 with an I2C module

I am trying to use an lcd screen on my stm32F3discovery.
The screen is made of an lcd 16 characters on 2 lines and an I2C module.
Here is the link of the product:
https://www.aliexpress.com/item/32763867041.html?spm=a2g0s.9042311.0.0.27424c4dsV7dLS
On the back of the screen I can see written: QAPASS 1602A
On the chip of the I2C module I can see written: PCF8574T
Here is the datasheet of the chip:
https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf
I tried to follow this tutoriel (the closest from what I am trying to do):
https://www.youtube.com/watch?v=1COFk1M2tak
I use the HAL library, the main function to send data is "HAL_I2C_Master_Transmit".
Here is the description of the function in "HAL_I2C_Master_Transmit":
#brief Transmits in master mode an amount of data in blocking mode.
#param hi2c Pointer to a I2C_HandleTypeDef structure that contains the configuration information for the specified I2C.
#param DevAddress Target device address: The device 7 bits address value in datasheet must be shifted to the left before calling the interface
#param pData Pointer to data buffer
#param Size Amount of data to be sent
#param Timeout Timeout duration
#retval HAL status
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
//I initialise a buffer
//I use a for loop to find the address of my slave: 0x3D (even tho on the //datasheet it's 0x3F, looks like A1 is bridged :O )
//I use the HAL_I2C_Master_Transmit function
//I move the address one bit to the left
//I reuse the HAL_I2C_Master_Transmit
//Nothing happens on the screen
//Here is my code (I tried to remove the useless comments):
#include "main.h"
I2C_HandleTypeDef hi2c1; // Init generated bu CubeMX
SPI_HandleTypeDef hspi1; // Init generated bu CubeMX
PCD_HandleTypeDef hpcd_USB_FS; // Init generated bu CubeMX
uint16_t adresseLCD; // the variable I put the slave address on
uint8_t buffer[]="123"; // The buffer I wanna see on the screen
void SystemClock_Config(void); // Generated by CubeMX
static void MX_GPIO_Init(void); // Generated by CubeMX
static void MX_I2C1_Init(void); // Generated by CubeMX
static void MX_SPI1_Init(void); // Generated by CubeMX
static void MX_USB_PCD_Init(void); // Generated by CubeMX
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_USB_PCD_Init();
adresseLCD=0x3D;
HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 1, 1000);
adresseLCD=adresseLCD*2; // Yes I could have used "adresseLCD<<1" but I
//am not used to that
HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 1, 1000);
while(1)
{
}
}
I expected something to show on the screen (even random values) but nothing appears (it lights up though).
I get no error (only warnings because I use "1" instead of "Pin_ON" when I WritePIn)
You expect it wrong.
First of allŠ± the I2C module, which is soldered on back, it is just simple serial-to parallel convertor. When you write data on I2C bus, it sets its 8 outputs according to 8 received bits in data bytes. When you read data bytes, it switches into input mode and read logical levels on 8 pins and transmits it over serial wire. More detailed description you can read in the datasheet on PCF8574 you have provided.
I.e. this part does not perform any "magic" which will take characters on input and output them on display. That means the outputting of random data is futile.
You need to know two things more:
how this module is connected to the display driver
what kind of display driver is used and how to utilize it.
Answer to the first question may be found in the Internet:
(taken from here)
You can see the display is connected in 4-bit mode, outputs P4-P7 (i.e. what you transmit in four most significant bits of data bytes) are connected to data lines of the display, while outputs P0-P2 are connected to control lines RS, R/W, EH and P3 is used to control the backlight.
Knowing this we came to the second question. I can only suggest, but more likely your display module have Hitachi HD44780 IC on it. In the datasheet on it you can found the information what data should be output on the control lines.
You can find pin description at page 8:
bit RS selects whatever it be a command (0) or a data (1)
bit R/W chooses write opertion (0) or read (1)
and bit E is actually a strobe. On the falling edge, i.e. when it changes from 1 to 0, the display driver reads data from data lines. That means to pass 4 bits of data you should perform 2 write operations: first one with bit 2 is set high, second with all other bits are the same, but the bit 2 is zero.
Now you can read list of instructions at page 25 of datasheet. And initialization sequence for the 4-bit mode at page 46 (Figure 24). Note for each line of bits there you actually send 2 data bytes: with bit 2 high and then with bit 2 low.
Note, in 4-bit mode all commands and data consist of two write phases: first - top half, then bottom half of a byte. Each phase is 2 data writes to I2C module, with E bit high and low, i.e. you'll need to send 4 bytes to output 1 byte of data.
So basically in order to transmit data from you STM32 to the LCD display driver (HD44780) you need to emulate the latter's interface signalling via the I2C interface chip (PCF8574).
In other words, MCU will send I2C commands that will toggle the I2C "backpack" chip such that it should emulate the right signaling for the LCD driver.
This happens somehow easy whne you are using the HAL_I2C_Master_*() methods. In the buffer array you specify the state of the pins on the LCD as you want them and in the order [0], [1], [2]... etc. For example, let's say that we have DB[7:4] connected to the upper 4 bits of the PCF I2C expander. We can setup the following:
buffer[0] = 0xD0 ; // 0b11010000;
buffer[1] = 0xA0 ; // 0b10100000;
buffer[2] = 0xF0 ; // 0b11110000;
HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 3, 10); // Note 3 bytes are sent
Once the buffer is prepared, the HAL_I2C_Master_Transmit() call will send the tree bytes consecutively, thus toggling the DB pins as you have mentioned:
DB7: 1 -> 1 -> 1
DB6: 1 -> 0 -> 1
DB5: 0 -> 1 -> 1
DB4: 1 -> 0 -> 1
The same can be applied to all 8 pins on the PCF chip. It is also worth noticing that this sequential IO update also creates a bit less of I2C communication overhead as it only addresses the I2C slave chip once :) .
By the way, I am currently working on a LCD over I2C Library for STM32F1xx (probably it will fit other STM32F series). You can check it out on github (still WIP):
https://github.com/meteowrite/stm32_i2cLcd
Cheers

Why does sending CMD58 over SPI to my Class 10 SD return 0x01 instead of 0x00?

I am trying to initialize an SD card using an SPI bus and STM32F4 Discovery Board. I am mainly relying on Elm Chan's implementation of the disk_initialize function in the example code to base my own implementation. Unfortunately, I have run into an issue where sending CMD58 to the SD card during the initialization process return a result of 0x01, which implies that the SD card is idle. However, I am still seeing the next four bytes from the SD card as 0x00, 0xFF, 0x80, 0x00 which is in the right format for an R3 response. However, I am not sure if I can trust these four bytes as my OCR.
As of now, I have tried ignoring that the SD card is idling and simply tried to use the next four bytes as the OCR but the code seems to fail at other points during the mounting process with respect to the type of the card being assumed from the OCR.
if (Timer1 && SD_SendCmd(CMD58, 0) == 0) {
for (n = 0; n < 4; n++) {
ocr[n] = SPI_RxByte();
}
type = (ocr[0] & 0x40) ? 6 : 2;
}
The code segment above is where I am first seeing the idle response. SD_SendCmd is where I send CMD58 to the SD card and where I am receiving 0x01 as the leftmost byte of the five byte response. Because I am not receiving 0x00, which signals that the SD card has no issues with the command passed to it, the code breaks out of the initialization process and returns an error. I would greatly appreciate any help with this matter as I have been stumped by this 0x01 return value for quite some time now. Thank you!
So I was able to figure out the issue. It turns out that the card I was using was an SDHC card, where HC stands for high capacity. According to the simplified SD card specification, the CRC, which is sent at the end of the transmission of a command has to have the least significant bit set to 1. So, ORing the CRC with 0x01 before any of the transmissions let me initialize and use any type of SD card. So the issue I was having was not from CMD58, but how I was dealing with the CRC in general. Interestingly enough, not ORing the CRC seems to work fine with non high-capacity SD cards. But ORing the CRC with 0x01 seems to work with all cards (at least as far as I have tested).
With regard to ORing the CRC with 0x01, this is not the CRC, but the STOP-BIT, the CRC is of type CRC7 and is at bits 1:7 of byte #6 in the command. According to the specification, even if the CRC is not required, the stop bit must always be 1.

how to create image programmatically

Is it possible to create bitmap programmatically in C?
I want to pass it some text to draw, e.g.
createBitmapWithContents("Hello");
or
createBitmapWithContents("Hello \n other line");
And it should create bitmap which has "Hello" drawn in it (or draw second text respectively).
Also, the text "Hello" might be a Unicode string. Not necessarily English characters.
Preferably I would like to do this without using some third party libraries.
You'll need to do two different things :
Generate an image in memory that represents your string
Store that image into a file
Both can be done without external libraries (using simple predefined patterns of characters and storing as simple format such as BMP).
But note that it would be a lot easier to do this using a high-level image drawing library such as OpenCV or ImageMagick.
The first thing to do is to is to define a data structure to store your image, something like this:
struct Image {
int height, width;
unsigned char* pixels;
};
Then you'll have to generate the functions to allocate the image, free the image and maybe something to copy an image inside another one.
In order to print your character on your image, you would have to create predefined patterns like this:
char patternA[] = {
0x00, 0x00, 0xff, 0x00, 0x00
0x00, 0xff, 0x00, 0xff, 0x00
0x00, 0xff, 0x00, 0xff, 0x00
0x00, 0xff, 0xff, 0xff, 0x00
0x00, 0xff, 0x00, 0xff, 0x00
0x00, 0xff, 0x00, 0xff, 0x00
0x00, 0xff, 0x00, 0xff, 0x00
};
Image imageOfA;
imageOfA.width = 5;
imageOfA.height= 7;
imageOfA.pixels= patternA;
You can also read those patterns from image files or even better, from a font file (but without external libraries, you'll need to implement the file readers yourself).
Once you have your patterns of characters, you can combine those predefined images to create a new image corresponding to your input string.
Finally, you'll have to write your image structure into a file. For that, you can either use a low-level library (such as libjpeg or libpng) or you can implement it yourself using a simple file format (such as BMP).
The conclusion is that you really want to use a third party library to achieve what you want.
Did you try googling this?
There's quite a few things you could do, for example you can you can run loops to create your own matrix of pixels. check this link here

Resources