STM32 DMA: bytes remaining in buffer, encoded? - stm32
For quite a while now I've been struggling with DMA communication with two STM32 boards in some form or another. My current issue is as follows.
I have a host (a Raspberry Pi) running the following code, waiting for the board to initialise communication:
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
unsigned int usbdev;
unsigned char c;
system("stty -F /dev/ttyUSB0 921600 icanon raw");
usbdev = open("/dev/ttyUSB0", O_RDWR);
setbuf(stdout, NULL);
fprintf(stderr, "Waiting for signal..\n");
while (!read(usbdev, &c, 1));
unsigned char buf[] = "Defend at noon\r\n";
write(usbdev, buf, 16);
fprintf(stderr, "Written 16 bytes\r\n");
while (1) {
while (!read(usbdev, &c, 1));
printf("%c", c);
}
return 0;
}
Basically it waits for a single byte of data before it'll send "Defend at noon" to the board, after which it prints everything that is sent back.
The boards first send out a single byte, and then wait for all incoming data, replace a few bytes and send it back. See the code at the end of this post. The board can be either an STM32L100C or an STM32F407 (in practice, the discovery boards); I'm experiencing the same behaviour with both at this point.
The output I'm seeing (on a good day - on a bad day it hangs on Written 16 bytes) is the following:
Waiting for signal..
Written 16 bytes
^JDefend adawnon
As you can see, the data is sent and four bytes are replaced as expected, but there's an extra two characters in front (^J, or 0x5E and 0x4A). These turn out to be a direct consequence of the signal_host function. When I replace the character with something arbitrary (e.g. x), that is what's being output at that position. It is interesting to note that \n actually gets converted to its caret notation ^J somewhere along the road. It appears that this occurs in the communication to the board, because when I simply hardcode a string in the buffer and use dma_transmit to send that to an non-interactive host program, it gets printed just fine.
It looks like I've somehow miss-configured DMA in the sense that there's some buffer that is not being cleared properly. Additionally, I do not really trust the way the host-side program is using stty.. However, I've actually had communication working flawlessly in the past, using this exact code. I compared it to the code stored in my git history across several months, and I cannot find the difference/flaw.
Note that the code below uses libopencm3 and is based on examples from libopencm3-examples.
STM32L1 code:
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/dma.h>
void clock_setup(void)
{
rcc_clock_setup_pll(&clock_config[CLOCK_VRANGE1_HSI_PLL_32MHZ]);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART2);
rcc_periph_clock_enable(RCC_DMA1);
}
void gpio_setup(void)
{
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3);
gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3);
}
void usart_setup(int baud)
{
usart_set_baudrate(USART2, baud);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_enable(USART2);
}
void dma_request_setup(void)
{
dma_channel_reset(DMA1, DMA_CHANNEL6);
nvic_enable_irq(NVIC_DMA1_CHANNEL6_IRQ);
dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t) &USART2_DR);
dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_VERY_HIGH);
dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);
dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL6);
dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL6);
dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL6);
}
void dma_transmit_setup(void)
{
dma_channel_reset(DMA1, DMA_CHANNEL7);
nvic_enable_irq(NVIC_DMA1_CHANNEL7_IRQ);
dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t) &USART2_DR);
dma_set_read_from_memory(DMA1, DMA_CHANNEL7);
dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_VERY_HIGH);
dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
dma_disable_transfer_error_interrupt(DMA1, DMA_CHANNEL7);
dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL7);
dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL7);
}
void dma_request(void* buffer, const int datasize)
{
dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buffer);
dma_set_number_of_data(DMA1, DMA_CHANNEL6, datasize);
dma_enable_channel(DMA1, DMA_CHANNEL6);
signal_host();
usart_enable_rx_dma(USART2);
}
void dma_transmit(const void* buffer, const int datasize)
{
dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) buffer);
dma_set_number_of_data(DMA1, DMA_CHANNEL7, datasize);
dma_enable_channel(DMA1, DMA_CHANNEL7);
usart_enable_tx_dma(USART2);
}
int dma_done(void)
{
return !((DMA1_CCR6 | DMA1_CCR7) & 1);
}
void dma1_channel6_isr(void) {
usart_disable_rx_dma(USART2);
dma_clear_interrupt_flags(DMA1, DMA_CHANNEL6, DMA_TCIF);
dma_disable_channel(DMA1, DMA_CHANNEL6);
}
void dma1_channel7_isr(void) {
usart_disable_tx_dma(USART2);
dma_clear_interrupt_flags(DMA1, DMA_CHANNEL7, DMA_TCIF);
dma_disable_channel(DMA1, DMA_CHANNEL7);
}
void signal_host(void) {
usart_send_blocking(USART2, '\n');
}
int main(void)
{
clock_setup();
gpio_setup();
usart_setup(921600);
dma_transmit_setup();
dma_request_setup();
unsigned char buf[16];
dma_request(buf, 16); while (!dma_done());
buf[10] = 'd';
buf[11] = 'a';
buf[12] = 'w';
buf[13] = 'n';
dma_transmit(buf, 16); while (!dma_done());
while(1);
return 0;
}
STM32F4 code:
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/dma.h>
void clock_setup(void)
{
rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART2);
rcc_periph_clock_enable(RCC_DMA1);
}
void gpio_setup(void)
{
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3);
gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3);
}
void usart_setup(int baud)
{
usart_set_baudrate(USART2, baud);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_enable(USART2);
}
void dma_request_setup(void)
{
dma_stream_reset(DMA1, DMA_STREAM5);
nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ);
dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &USART2_DR);
dma_set_transfer_mode(DMA1, DMA_STREAM5, DMA_SxCR_DIR_PERIPHERAL_TO_MEM);
dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_VERY_HIGH);
dma_disable_peripheral_increment_mode(DMA1, DMA_SxCR_CHSEL_4);
dma_enable_memory_increment_mode(DMA1, DMA_STREAM5);
dma_disable_transfer_error_interrupt(DMA1, DMA_STREAM5);
dma_disable_half_transfer_interrupt(DMA1, DMA_STREAM5);
dma_disable_direct_mode_error_interrupt(DMA1, DMA_STREAM5);
dma_disable_fifo_error_interrupt(DMA1, DMA_STREAM5);
dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5);
}
void dma_transmit_setup(void)
{
dma_stream_reset(DMA1, DMA_STREAM6);
nvic_enable_irq(NVIC_DMA1_STREAM6_IRQ);
dma_set_peripheral_address(DMA1, DMA_STREAM6, (uint32_t) &USART2_DR);
dma_set_transfer_mode(DMA1, DMA_STREAM6, DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
dma_set_peripheral_size(DMA1, DMA_STREAM6, DMA_SxCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_STREAM6, DMA_SxCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_STREAM6, DMA_SxCR_PL_VERY_HIGH);
dma_disable_peripheral_increment_mode(DMA1, DMA_SxCR_CHSEL_4);
dma_enable_memory_increment_mode(DMA1, DMA_STREAM6);
dma_disable_transfer_error_interrupt(DMA1, DMA_STREAM6);
dma_disable_half_transfer_interrupt(DMA1, DMA_STREAM6);
dma_disable_direct_mode_error_interrupt(DMA1, DMA_STREAM6);
dma_disable_fifo_error_interrupt(DMA1, DMA_STREAM6);
dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM6);
}
void dma_request(void* buffer, const int datasize)
{
dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) buffer);
dma_set_number_of_data(DMA1, DMA_STREAM5, datasize);
dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_4);
dma_enable_stream(DMA1, DMA_STREAM5);
signal_host();
usart_enable_rx_dma(USART2);
}
void dma_transmit(const void* buffer, const int datasize)
{
dma_set_memory_address(DMA1, DMA_STREAM6, (uint32_t) buffer);
dma_set_number_of_data(DMA1, DMA_STREAM6, datasize);
dma_channel_select(DMA1, DMA_STREAM6, DMA_SxCR_CHSEL_4);
dma_enable_stream(DMA1, DMA_STREAM6);
usart_enable_tx_dma(USART2);
}
int dma_done(void)
{
return !((DMA1_S5CR | DMA1_S6CR) & 1);
}
void dma1_stream5_isr(void) {
usart_disable_rx_dma(USART2);
dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF);
dma_disable_stream(DMA1, DMA_STREAM5);
}
void dma1_stream6_isr(void) {
usart_disable_tx_dma(USART2);
dma_clear_interrupt_flags(DMA1, DMA_STREAM6, DMA_TCIF);
dma_disable_stream(DMA1, DMA_STREAM6);
}
void signal_host(void) {
usart_send_blocking(USART2, '\n');
}
int main(void)
{
clock_setup();
gpio_setup();
usart_setup(921600);
dma_transmit_setup();
dma_request_setup();
unsigned char buf[16];
dma_request(buf, 16); while (!dma_done());
buf[10] = 'd';
buf[11] = 'a';
buf[12] = 'w';
buf[13] = 'n';
dma_transmit(buf, 16); while (!dma_done());
while(1);
return 0;
}
Well, I can be brief about this one.
I recommend against using stty for this sort of thing. I realise I have probably not configured stty properly, and with some option-tweaking it is probably possible to get it right, but it's completely unclear. I ended up throwing it out the window and using pyserial instead. I should've done that weeks ago. The above STM32 code works fine and the required Python code is completely trivial.
#!/usr/bin/env python3
import serial
dev = serial.Serial("/dev/ttyUSB0", 921600)
dev.read(1) # wait for the signal
dev.write("Defend at noon\r\n".encode('utf-8'))
while True:
x = dev.read()
print(x.decode('utf-8'), end='', flush=True)
Related
Multiple write to external eeprom corrupts previous data
I am interfacing AT24C02 external eeprom using stm32f401 nucleo. I am facing few issues. Lets consider some address /* 24c02 Device Address */ #define EEPROM_ADDRESS (uint8_t)0xA0 /*Demo addr*/ #define DEMO_BYTE_ADDR (uint16_t)0x01 #define DEMO_WORD_ADDR (uint16_t)0x02 #define DEMO_FLOAT_ADDR (uint16_t)0x06 #define DEMO_STRING_ADDR (uint16_t)0x0A 1. Writing and reading simultaneously. I am able to write and read data to and from eeprom simultaneously. /*Writing Byte*/ uint8_t byte; eep_write_byte(DEMO_BYTE_ADDR, 50); eep_read_byte(DEMO_BYTE_ADDR, &byte); /*Wrinting word*/ uint32_t word; eep_write_word(DEMO_WORD_ADDR, 123456789); word = eep_read_word(DEMO_WORD_ADDR); /*Writing float*/ float fData; eep_write_float(DEMO_FLOAT_ADDR, 9876.54); fData = eep_read_float(DEMO_FLOAT_ADDR); This code works fine. Below is the snapshot of output. 2. Problems with writing string After the above portion of code i have written some lines to write string and read string. As you can see in output buffer dest contains some value. uint8_t dest[50] = {0}; eep_write_string(DEMO_STRING_ADDR, (uint8_t*)"Hello World!", strlen("Hello World!")); eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!")); 3. After writing all these values the reading shows corrupted data After the above portion of the code if i read back all the addresses i have wrote gives me corrupted data. eep_read_byte(DEMO_BYTE_ADDR, &byte); word = eep_read_word(DEMO_WORD_ADDR); fData = eep_read_float(DEMO_FLOAT_ADDR); eep_read_string(DEMO_STRING_ADDR, dest, strlen("Hello World!")); Below is the snapshot of out for this code. As you can see all the data is now corrupted. you can find eeprom.c from this link https://pastebin.com/2vYWYhnw or just scroll below. /* * eeprom.c * * Created on: 04-Jan-2021 * Author: DEVJEET MANDAL */ #include "i2c.h" #include "eeprom.h" #include "stdio.h" #include "stdlib.h" /* Low Level function */ void eep_small_delay(void) { for (uint32_t i = 0; i < 65535; i++) __asm__("NOP"); } void i2c_error(void) { HAL_I2C_DeInit(&hi2c1); //De-init i2c bus __asm__("NOP"); HAL_I2C_Init(&hi2c1); //re-init i2c bus __asm__("NOP"); } eep_status_t i2c_write(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) { HAL_StatusTypeDef xStatus = HAL_ERROR; xStatus = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100); HAL_Delay(5); if (xStatus != HAL_OK) {i2c_error();} return xStatus; } eep_status_t i2c_read(uint16_t u8_reg_addr, uint8_t *u8_data, uint16_t len) { HAL_StatusTypeDef xStatus = HAL_ERROR; xStatus = HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDRESS, u8_reg_addr, I2C_MEMADD_SIZE_16BIT, u8_data, len, 100); eep_small_delay(); if (xStatus != HAL_OK) {i2c_error();} return xStatus; } /* High Level Functions */ eep_status_t eep_write_byte(uint16_t u8_reg_addr, uint8_t u8_data) { return i2c_write(u8_reg_addr, &u8_data, 1); } eep_status_t eep_read_byte(uint16_t u8_reg_addr, uint8_t *u8_data) { return i2c_read(u8_reg_addr, u8_data, 1); } eep_status_t eep_is_data_avaiable(void) { eep_status_t xStatus = EEP_ERROR; uint8_t data = 0; eep_read_byte(EEPROM_DATA_AVAILABLE_ADDR, &data); if (data == 0) {xStatus = EEP_ERROR;} else if (data == 1) {xStatus = EEP_OK;} else {xStatus = EEP_ERROR;} return xStatus; } eep_status_t eep_set_data_available(uint8_t val) { return eep_write_byte(EEPROM_DATA_AVAILABLE_ADDR, val); } eep_status_t eep_write_word(uint16_t reg_addr, uint32_t value) { uint8_t val_byte[4] = {0}; val_byte[0] = (value >> 24) & 0xFF; val_byte[1] = (value >> 16) & 0xFF; val_byte[2] = (value >> 8) & 0xFF; val_byte[3] = (value >> 0) & 0xFF; return i2c_write(reg_addr, val_byte, 4); } eep_status_t eep_write_float(uint16_t reg_addr, float value) { union FtoHex{ float fval; uint32_t hval; }float_to_hex; float_to_hex.fval = value; return eep_write_word(reg_addr, float_to_hex.hval); } uint32_t eep_read_word(uint16_t reg_addr) { uint8_t val_buff[4] = {0}; i2c_read(reg_addr, val_buff, 4); return ((val_buff[0] << 24) | (val_buff[1] << 16) | (val_buff[2] << 8) | (val_buff[3] << 0)); } float eep_read_float(uint8_t reg_addr) { union FtoHex{ float fval; uint32_t hval; }float_to_hex; float_to_hex.hval = eep_read_word(reg_addr); return float_to_hex.fval; } void eep_write_string(uint16_t reg_addr, uint8_t *src, uint16_t len) { i2c_write(reg_addr, src, len); } void eep_read_string(uint16_t reg_addr, uint8_t *dest, uint16_t len) { i2c_read(reg_addr, dest, len); } //--------------------------------------------------------------------- Almost forgot to mention i m running I2C #400Khz. Though i have tried 100KHz which results same. Below is the HAL generated I2C init. /* I2C1 init function */ void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } Now the question is why this problem. Basically the HAL should take care of all the situation and i will just send data to it. Any help will be appreciated. Regards.
You missed that AT24C02 is organized in 16 byte (write) pages. The corruption is caused by rollover/wrap # offset 0x0F when writing the string starting # offset 0x0A. See the data sheet for details.
I have a timing problem between read and write on a serial channel in gtk
This program is intended to communicate over an unreliable serial channel via a PL2303 usb converter with a distant microcontroller. The main loop uses g_io_add_watch to listen for data from the micro. It then calls g_io_read_chars to read the data and g_io_write_chars to send a one-byte acknowledge. The micro echos this back. The read and write are called from within ReadStationMessage. If the micro is slow to respond, the ReadStationMessage() function is called twice, once to read the data and again to receive the echo. However, if it responds immediately, ReadStationMessage() is called only once and the echo byte is appended to the data. I don't understand how this is possible when g_io_write_chars does not send the acknowledge until after g_io_read_chars returns and the micro does nothing until it receives the acknowledge. #include <gtk/gtk.h> #include <errno.h> #include <fcntl.h> #include <termios.h> int set_interface_attribs(int fd, int speed) { struct termios tty; if (tcgetattr(fd, &tty) < 0) { g_print("Error from tcgetattr: %s\n", strerror(errno)); return -1; } cfmakeraw(&tty); cfsetospeed(&tty, (speed_t)speed); cfsetispeed(&tty, (speed_t)speed); tty.c_cc[VMIN] = 0; tty.c_cc[VTIME] = 1; if (tcsetattr(fd, TCSANOW, &tty) != 0) { g_print("Error from tcsetattr: %s\n", strerror(errno)); return -1; } return 0; } static gboolean ReadStationMessage( GIOChannel *channel, GIOCondition condition, guchar* user_data ) { guchar buf[128]; gsize bytes_read, bytes_written; gint i; g_print("\nentering ReadStationMessage\n"); g_io_channel_read_chars( channel, buf, 128, &bytes_read, NULL ); for( i=0; i<bytes_read; i++ ) g_print("%u ", buf[i]); buf[0] = 0; g_io_channel_write_chars( channel, buf, 1, &bytes_written, NULL ); return TRUE; } int main( int argc, char *argv[] ) { char *portname = "/dev/ttyUSB0"; gint fd; GIOChannel *channel; static guchar user_data[128]; GError *error=NULL; guint EventSource_id; fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC ); set_interface_attribs(fd, B9600); channel = g_io_channel_unix_new(fd); g_io_channel_set_encoding(channel, NULL, &error); // raw data, no encoding GIOCondition condition = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL; gtk_init (&argc, &argv); EventSource_id = g_io_add_watch( channel, condition, (GIOFunc) ReadStationMessage, user_data ); return 0; }
Fixed! I need to g-io-channel-flush after write.
Segmentation fault on scanf?
I don't understand why the scanf call causes segmentation error. Tried making a separate file with only int number and scanf and it worked no problem. Really confused here need help. I use pointer in the scanf parameter so I'm suspecting the error might come from the interaction between scanf and shared memory somehow? #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/shm.h> #include <sys/stat.h> #include <sys/mman.h> #include <semaphore.h> int main() { const char *name = "message"; const char *names = "sem"; const int SIZE = 4096; const int size = 1; int number; int shm_fd1; int shm_fd2; char *ptr; // Pointer to shared memory sem_t *sem; /* create the shared memory segment */ shm_fd1 = shm_open(name, O_CREAT | O_RDWR, 0666); shm_fd2 = shm_open(names, O_CREAT | O_RDWR, 0666); /* configure the size of the shared memory segment */ ftruncate(shm_fd1, SIZE); ftruncate(shm_fd2, size); /* initialize semaphore */ if (sem_init(sem, 1, 1) < 0) { // 1 = multiprocess fprintf(stderr, "ERROR: could not initialize semaphore.\n"); exit(0); } /* now map the shared memory segment in the address space of the process */ ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd1, 0); sem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd2, 0); if (ptr == MAP_FAILED) { printf("Map failed\n"); return -1; } if (sem == MAP_FAILED) { printf("Map failed\n"); return -1; } strcpy(ptr, "Hello from the server\n"); /* store and read from the shared memory region */ printf("Message: %s\n", ptr); printf("0. Quit\n 1. Change message\n 2. Check message\n"); printf("Type an integer: "); scanf("%d", &number); //confirmed this causes the error if I remove the line above the program runs no problem. the part alone also works fine apart from this file. if (number == 1) { sem_wait(sem); printf("Enter your message: "); scanf("%s", ptr); sem_post(sem); } else if (number == 2) { printf("Message: %s\n", ptr); } else { /*break;*/ } /* remove the shared memory segment */ if (shm_unlink(name) == -1) { printf("Error removing %s\n",name); exit(-1); } return 0; }
map reserver memory at boot to user space using remap_pfn_range
I am trying to map reserved memory (30M with offset of 2G) at boot time (boot kernel parameters mem=2G memmap=30M$2G) to user space using the remap_pfn_range, bellow is my driver code: #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/mm.h> #include <asm/uaccess.h> // #include <asm/error.h> #define MAP_MAJOR 150 #define RAW_DATA_SIZE 0x1E00000 // 30 Mo #define RAW_DATA_OFFSET 0x80000000 //2G int results; static void *rawdataStart = NULL; static int map_mmap(struct file *filp, struct vm_area_struct *vma); struct file_operations map_fops = { .open = nonseekable_open, .mmap = map_mmap }; static int map_mmap(struct file *filp, struct vm_area_struct *vma) { if (rawdataStart == NULL) { printk(KERN_ERR "Memory not mapped!\n"); return -EAGAIN; } if ((vma->vm_end - vma->vm_start) != RAW_DATA_SIZE) { printk(KERN_ERR "Error: sizes don't match (buffer size = %d, requested size = %lu)\n", RAW_DATA_SIZE, vma->vm_end - vma->vm_start); return -EAGAIN; } results = remap_pfn_range(vma, vma->vm_start, RAW_DATA_OFFSET >> PAGE_SHIFT, RAW_DATA_SIZE, PAGE_SHARED); if (results != 0) { printk(KERN_ERR "Error in calling remap_pfn_range: returned %d\n", results); return -EAGAIN; } return 0; } static int __init map_init(void) { printk("init map module\n"); if (register_chrdev(MAP_MAJOR,"mapReserved", &map_fops) <0 ) { printk("unable to get major for map module\n"); return -EBUSY; } rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE); if (rawdataStart == NULL) { printk(KERN_ERR "Unable to remap memory\n"); return 1; } printk(KERN_INFO "ioremap returned %p\n", rawdataStart); return 0; } void __exit map_cleanup(void) { printk("exit map module\n"); unregister_chrdev(MAP_MAJOR,"mapReserved"); if (rawdataStart != NULL) { printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart); iounmap(rawdataStart); } else { printk(KERN_WARNING "No memory to unmap!\n"); } return; } MODULE_LICENSE("GPL"); module_init( map_init); module_exit( map_cleanup); and my user space app is below #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #define RAW_DATA_SIZE 0x1E00000 int main(void) { void * data; int fd = open("/dev/mapReserved", O_RDWR); if (fd == -1) { perror("open error...\n"); return -1; } data = mmap(NULL, RAW_DATA_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096); close(fd); return 0; } when i insert the module it's return [ 873.621763] init map module [ 873.623175] ioremap returned fb580000 but when i am executing the user space app it's return error open error...
I've resolved this problem following those references : 1- Reserve memory in Linux driver module and share it using driver mmap 2- mmap of several GB of reserved memory using in my case i am reserving 30M from the offset 2G and bellow is the code module: // #include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/debugfs.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/mm.h> #include <linux/kdev_t.h> #include <asm/page.h> #include <linux/cdev.h> #include <linux/device.h> #ifndef VM_RESERVED # define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) #endif #define RAW_DATA_SIZE 31457280 #define RAW_DATA_OFFSET 0x80000000UL void *rawdataStart; struct dentry *file; /* * Open the device; in fact, there's nothing to do here. */ int simple_open (struct inode *inode, struct file *filp) { return 0; } /* * Closing is just as simpler. */ static int simple_release(struct inode *inode, struct file *filp) { return 0; } static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; unsigned long mapoffset; mapoffset = RAW_DATA_OFFSET + (vma->vm_pgoff << PAGE_SHIFT); ret = remap_pfn_range(vma, vma->vm_start, mapoffset >> PAGE_SHIFT, vma->vm_end - vma->vm_start, PAGE_SHARED); if ( ret != 0 ) { printk("Error remap_pfn_range. \n"); return -EAGAIN; } return 0; } /* Device uses remap_pfn_range */ static struct file_operations simple_remap_ops = { .owner = THIS_MODULE, .open = simple_open, .release = simple_release, .mmap = simple_remap_mmap, }; /* * Module housekeeping. */ static int simple_init(void) { file = debugfs_create_file("mmap_example", 0644, NULL, NULL, &simple_remap_ops); rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE); if (rawdataStart!=NULL){ printk("rawdataStart at:%p \n", rawdataStart); memset(rawdataStart, 'c', 20971520); memset(rawdataStart+20971520, '$', 100); }else{ printk("rawdataStart is NULL \n"); return -1; } return 0; } static void simple_cleanup(void) { debugfs_remove(file); if (rawdataStart != NULL) { printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart); iounmap(rawdataStart); } else { printk(KERN_WARNING "No memory to unmap!\n"); } } module_init(simple_init); module_exit(simple_cleanup); MODULE_AUTHOR("Jonathan Corbet"); MODULE_LICENSE("Dual BSD/GPL"); and the user space App: #include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> #define RAW_DATA_SIZE 31457280 int main(int argc, char **argv) { int configfd; char * address = NULL; unsigned long chkSum; FILE *fp = fopen("results.log", "w+"); configfd = open("/sys/kernel/debug/mmap_example", O_RDWR); if (configfd < 0) { perror("Open call failed"); return -1; } address = (unsigned char*) mmap(NULL, RAW_DATA_SIZE, PROT_WRITE, MAP_PRIVATE, configfd, 0); if (address == MAP_FAILED) { perror("mmap operation failed"); return -1; } fputs(address, fp); fclose(fp); close(configfd); return 0; }
C++ class member variable resetting to 0
I'm trying to increment and decrement the index of a list of readings, however, everytime I run update(), m_notifIndex gets set back to zero. I'm sorry if this type of question has been asked before, but after looking for the answer for an hour, I gave up and went on to ask my first question here. Sorry for the bad formatting too, again, this is my first time posting. Display.cpp #include "display.h" #include <time.h> #include <unistd.h> #include <iostream> Display::Display(unsigned int width, unsigned int height, unsigned int num_sensors, std::string* sensors, const std::string& dir, Message* messages) { m_notifIndex = 0; } void Display::update() { if (m_showNotif) { //when there are no more messages, show the notifications while (!m_notifications->isEmpty()) { //first draw the notification if there is a warning in the current index if (m_notifications->sensors[m_notifIndex] != NULL) { m_oled->clear(PAGE); drawSensor(); m_oled->display(); sleep(1); //keep updating the message and notif stack when there are no inputs while (m_a->pinRead() == HIGH && m_right->pinRead() == HIGH && m_left->pinRead() == HIGH && m_b->pinRead() == HIGH) { m_messages->updateMsgStack(); updateNotif(); if (!m_messages->isEmpty() || m_notifications->warnings[m_notifIndex]) return; //break away from the loop if a new message comes in } //listen in for inputs if (m_right->pinRead() == LOW) { //wait until the button is released while (m_right->pinRead() == LOW) {} if (m_notifIndex == m_num_sensors-1) m_notifIndex = 0; //wrap around when at the end else m_notifIndex++; } else if (m_left->pinRead() == LOW) { while (m_left->pinRead() == LOW) {} if (m_notifIndex == 0) m_notifIndex = m_num_sensors-1; //wrap around when at the beginning else m_notifIndex--; } else if (m_a->pinRead() == LOW) { while (m_a->pinRead() == LOW) {} m_showNotif = false; return; } checkForPanic(); } else { //when the current index has no warning if (m_notifIndex == m_num_sensors-1) m_notifIndex = 0; //wrap around when at the end else m_notifIndex++; } } } } void Display::updateNotif() { std::string line; for (unsigned int i = 0; i < sizeof(m_sensors)/sizeof(m_sensors[0]); i++) { const char* filePath = (m_notifDir + m_sensors[i] + ".txt").c_str(); if (m_messages->exists(filePath)) { usleep(10000); try { m_messages->m_incMsg.open(filePath); while(std::getline(m_messages->m_incMsg, line)) { m_notifications->addWarning (line, i); } m_messages->m_incMsg.close(); } catch (std::ios_base::failure& e) { std::cerr << e.what() << '\n' << std::endl; } } else m_notifications->removeWarning (i); //delete the warning when the file doesnt exist } } void Display::checkForPanic() { if (m_b->pinRead() == LOW) { time_t hold; time(&hold); while (m_b->pinRead() == LOW) { if (time(NULL) > hold + 3) { //if the timer reaches 3 seconds //m_messages->sendReply("Miner_Emergency"); return; } } } } Display.h #ifndef OLED_DISPLAY_H_ #define OLED_DISPLAY_H_ #include <sstream> #include <string> #include "image/image.h" #include "oled/Edison_OLED.h" #include "message.h" #include "DataStructs/Notif.h" #include "gpio/gpio.h" #define SLEEPTIMEOUT 20 class Display { public: Display(unsigned int width, unsigned int height, unsigned int num_sensors, std::string* sensors, const std::string& dir, Message* messages); void run(); ~Display(); private: edOLED* m_oled; const unsigned int m_height, m_width; Image* m_miner; Image* m_checkin; Image* m_reminder; Image* m_blast; Image* m_go_to; Image* m_goto_zone; bool m_isSleeping, m_showNotif; time_t m_timer; Message* m_messages; std::string* m_sensors; std::string m_notifDir; NotifHandler* m_notifications; unsigned int m_notifIndex; const unsigned int m_num_sensors; gpio* m_up; gpio* m_down; gpio* m_left; gpio* m_right; gpio* m_a; gpio* m_b; void drawImage(Image* image); void update(); void drawMessage(MsgNode* message); void drawTime(); void drawSensor(); void updateNotif(); void checkForPanic(); }; #endif //OLED_DISPLAY_H_