I am trying to make a simple SPI Master/slave comunication between two ESP32, using this code as reference https://github.com/hideakitai/ESP32DMASPI
My code is (master) :
#include <stdio.h>
#include <stdint.h>
#include <Arduino.h>
#include "maspn18_e3_a_r2_c_can_cr09338.h"
#include <ESP32DMASPIMaster.h>
//#include <ESP32DMASPISlave.h>
#include <ESP32CAN.h>
#include <CAN_config.h>
#include <iostream>
#include <stdlib.h>
//#include <SPI.h>
/*
#include <string.h>
#include <math.h>
*/
// === [ START ] Master Configuration ===
ESP32DMASPI::Master master;
static const uint32_t BUFFER_SIZE = 8; // deve essere un multiplo di 4 ==> 8192
uint8_t* spi_master_tx_buf;
//uint8_t* spi_master_rx_buf;
uint8_t num_msg = 0;
uint8_t msg_src[]= {num_msg, 0x80, 0x4A, 0x0F, 0x00, 0x00, 0x00, 0x00};
//uint8_t msg_src[]= {0x00, 0x80, 0x4A, 0x0F, 0x00, 0x00, 0x00, 0x00};
void set_buffer() {
for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
spi_master_tx_buf[i] = msg_src[i];
//spi_master_tx_buf[i] = i & 0xFF;
}
//memset(spi_master_rx_buf, 0, BUFFER_SIZE);
}
// === [ STOP ] Master Configuration ===
using namespace std;
CAN_device_t CAN_cfg; // CAN Config
const int rx_queue_size = 10; // Receive Queue size
void setup() {
Serial.begin(115200);
Serial.println("CAN reader on primary CAN bus - MASTER SPI");
//CAN_cfg.speed = CAN_SPEED_500KBPS;
//CAN_cfg.tx_pin_id = GPIO_NUM_22;
//CAN_cfg.rx_pin_id = GPIO_NUM_21;
//CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
//////////// Init CAN Module
//ESP32Can.CANInit();
// === [ START ] Master setup ===
// to use DMA buffer, use these methods to allocate buffer
spi_master_tx_buf = master.allocDMABuffer(BUFFER_SIZE);
//spi_master_rx_buf = master.allocDMABuffer(BUFFER_SIZE);
set_buffer();
delay(5000);
master.setDataMode(SPI_MODE0); // default: SPI_MODE0
master.setFrequency(4000000); // default: 8MHz (too fast for bread board...) // 4000000
master.setMaxTransferSize(BUFFER_SIZE); // default: 4092 bytes
// begin() after setting
Serial.println("master.begin() - default: VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)");
master.begin(VSPI); // default: HSPI (CS: 15, CLK: 14, MOSI: 13, MISO: 12)
// === [ STOP ] Master setup ===
}
void loop() {
master.transfer(spi_master_tx_buf, BUFFER_SIZE);
printf("[%d] Send data ==>\n", msg_src[0]);
msg_src[0]++;
for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
spi_master_tx_buf[i] = msg_src[i];
//spi_master_tx_buf[i] = i & 0xFF;
}
delay(2000);
// === [ STOP ] Master loop ===
}
And for the slave :
#include <stdio.h>
#include <stdint.h>
#include <Arduino.h>
#include "maspn18_e3_a_r2_c_can_cr09338.h"
#include <ESP32DMASPISlave.h>
#include <ESP32CAN.h>
#include <CAN_config.h>
#include <iostream>
#include <stdlib.h>
#include <SPI.h>
/*
#include <string.h>
#include <math.h>
*/
// MASTER SPI ==> https://github.com/hideakitai/ESP32DMASPI/blob/master/examples/master_simple/master_simple.ino
ESP32DMASPI::Slave slave;
static const uint32_t BUFFER_SIZE = 8; // 8192
//uint8_t* spi_slave_tx_buf;
uint8_t* spi_slave_rx_buf;
using namespace std;
CAN_device_t CAN_cfg; // CAN Config
const int rx_queue_size = 10; // Receive Queue size
void setup() {
Serial.begin(115200);
Serial.println("CAN writer on second CAN bus - SLAVE SPI");
spi_slave_rx_buf = slave.allocDMABuffer(BUFFER_SIZE);
//set_buffer();
delay(5000);
// slave device configuration
slave.setDataMode(SPI_MODE0);
slave.setMaxTransferSize(BUFFER_SIZE);
// begin() after setting
//slave.begin(); // HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> default
// VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)
Serial.println("slave.begin(VSPI); - VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)");
slave.begin(VSPI);
}
void loop() {
// if there is no transaction in queue, add transaction
if (slave.remained() == 0) {
//slave.queue(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
slave.queue(spi_slave_rx_buf, BUFFER_SIZE);
}
// if transaction has completed from master,
// available() returns size of results of transaction,
// and buffer is automatically updated
while (slave.available()) {
printf("Received data ==> ");
// show received data
for (size_t i = 0; i < BUFFER_SIZE; ++i) {
printf("%d ", spi_slave_rx_buf[i]);
}
printf("\n");
slave.pop();
}
}
Basically it just sends a simple array over and over again with an incremental number in the first place. However, apparently at random, the comunication will "skip" a number or it will print the same a couple of time and then skip it. Image for reference :
Print of the received message on the slave:
What could be the cause of this problem?
I tried altering the frequence of the communication and i tried varying the buffer size to the smallest possible, but it does not seem to have any effect
Thanks a lot in advance
Related
Specific GPIO pin is connected to switch, upon pressing the switch the ISR needs to triggered. So I have the user space application to read the ISR, but I am getting the ISR on both the edges.
Receiving the interrupt when switch is pressed and also when released. How to configure to receive the ISR only on rising edge
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
int main(int argc, char *argv[]) {
int fd;
char value;
struct pollfd poll_gpio;
poll_gpio.events = POLLPRI;
// export GPIO
fd = open ("/sys/class/gpio/export", O_WRONLY);
write (fd, "44", 4);
close (fd);
// configure as input
fd = open ("/sys/class/gpio/gpio44/direction", O_WRONLY);
write (fd, "in", 3);
close (fd);
// configure interrupt
fd = open ("/sys/class/gpio/gpio44/edge", O_WRONLY);
write (fd, "rising", 7); // configure as rising edge
close (fd);
// open value file
fd = open("/sys/class/gpio/gpio44/value", O_RDONLY );
poll_gpio.fd = fd;
poll (&poll_gpio, 1, -1); // discard first IRQ
read (fd, &value, 1);
// wait for interrupt
while (1) {
poll (&poll_gpio, 1, -1);
if ((poll_gpio.revents & POLLPRI) == POLLPRI) {
lseek(fd, 0, SEEK_SET);
read (fd, &value, 1);
usleep (50);
printf("Interrupt GPIO val: %c\n", value);
}
}
close(fd); //close value file
return EXIT_SUCCESS;
}
I used gpio test driver also to test the ISR, but even in driver code I am getting ISR on both edges when the switch is pressed
Here is the gpio test driver code
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("A Button driver for the GPIO Switch");
MODULE_VERSION("0.1");
#define GPIO_NUM 44
#define GPIO_KEY_NAME "GPIO_INT_KEY"
static int irq;
/* interrupt handler*/
static irqreturn_t gpio_int_key_isr(int irq, void *dev_id)
{
printk(KERN_INFO "GPIO:Interrupt received. key: %s\n", GPIO_KEY_NAME);
return IRQ_HANDLED;
}
static int __init gpio_test_probe(struct platform_device *pdev)
{
int ret_val;
struct device *dev = &pdev->dev;
printk(KERN_INFO "GPIO Platform_probe enter\n");
gpio_request(GPIO_NUM, "sysfs");
gpio_direction_input(GPIO_NUM);
gpio_set_debounce(GPIO_NUM, 200);
gpio_export(GPIO_NUM, false);
irq = gpio_to_irq(GPIO_NUM);
if (irq < 0)
{
pr_err("IRQ is not available\n");
return -EINVAL;//1;
}
printk(KERN_INFO "IRQ using gpio_to_irq: %d\n", irq);
/*Register the interrupt handler*/
ret_val = devm_request_irq(dev, irq, gpio_int_key_isr, IRQF_TRIGGER_RISING, GPIO_KEY_NAME, pdev->dev.of_node);
if(ret_val)
{
pr_err("Failed to request GPIO interrupt %d, error %d\n",irq, ret_val);
return ret_val;
}
return 0;
}
static int __exit gpio_test_remove(struct platform_device *pdev)
{
pr_info("%s function is called. \n",__func__);
return 0;
}
/*Declare list of devices supported by the driver*/
static const struct of_device_id my_of_ids[] = {
{ .compatible = "gpio-intr-key"},
{},
};
MODULE_DEVICE_TABLE(of, my_of_ids);
/*Define platform driver structure*/
static struct platform_driver my_platform_driver = {
.probe = gpio_test_probe,
.remove = gpio_test_remove,
.driver = {
.name = "gpioIntrKey",
.of_match_table = of_match_ptr(my_of_ids),
.owner = THIS_MODULE,
}
};
module_platform_driver(my_platform_driver);
Below is the dts entry
gpio_test {
compatible = "gpio-intr-key";
gpio = <&gpio2a 44>;
interrupt-controller;
interrupt-parent = <&gpio2a>;
interrupts = <44 IRQ_TYPE_EDGE_RISING>;
status = "okay";
};
i am new in linux kernel module developpement and i am searching for sharing a memory segment from kernel module to user space process to escape latency of copying data.
i am using the sys v shared memory api, when i share memory between two process it's work fine, but i am not able to share memory between process and kernel module.
bellow is my code of the kernel module and the user space app
server side : module
#include <linux/module.h> // init_module, cleanup_module //
#include <linux/kernel.h> // KERN_INFO //
#include <linux/types.h> // uint64_t //
#include <linux/kthread.h> // kthread_run, kthread_stop //
#include <linux/delay.h> // msleep_interruptible //
#include <linux/syscalls.h> // sys_shmget //
#define BUFSIZE 100
#define SHMSZ BUFSIZE*sizeof(char)
key_t KEY = 5678;
static struct task_struct *shm_task = NULL;
static char *shm = NULL;
static int shmid;
static int run_thread( void *data )
{
char strAux[BUFSIZE];
shmid = sys_shmget(KEY, SHMSZ, IPC_CREAT | 0666);
if( shmid < 0 )
{
printk( KERN_INFO "SERVER : Unable to obtain shmid\n" );
return -1;
}
shm = sys_shmat(shmid, NULL, 0);
if( !shm )
{
printk( KERN_INFO "SERVER : Unable to attach to memory\n" );
return -1;
}
strncpy( strAux, "hello world from kernel module", BUFSIZE );
memcpy(shm, strAux, BUFSIZE);
return 0;
}
int init_module()
{
printk( KERN_INFO "SERVER : Initializing shm_server\n" );
shm_task = kthread_run( run_thread, NULL, "shm_server" );
return 0;
}
void cleanup_module()
{
int result;
printk( KERN_INFO "SERVER : Cleaning up shm_server\n" );
result = kthread_stop( shm_task );
if( result < 0 )
{
printk( KERN_INFO "SERVER : Unable to stop shm_task\n" );
}
result = sys_shmctl( shmid, IPC_RMID, NULL );
if( result < 0 )
{
printk( KERN_INFO
"SERVER : Unable to remove shared memory from system\n" );
}
}
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( " MBA" );
MODULE_DESCRIPTION( "Shared memory server" );
client side : process
#include <sys/ipc.h> // IPC_CREAT, ftok //
#include <sys/shm.h> // shmget, ... //
#include <sys/sem.h> // semget, semop //
#include <stdio.h> // printf //
#include <string.h> // strcpy //
#include <stdint.h> // uint64_t //
#define BUFSIZE 4096
key_t KEY = 5678;
int main(int argc, char *argv[]) {
int shmid, result;
char *shm = NULL;
shmid = shmget(KEY, BUFSIZE, 0666);
if (shmid == -1) {
perror("shmget");
exit(-1);
}
shm = shmat(shmid, NULL, 0);
if (!shm) {
perror("shmat");
exit(-1);
}
printf("%s\n", shm);
result = shmdt(shm);
if (result < 0) {
perror("shmdt");
exit(-1);
}
}
any suggestion or document can help.
System calls are not intended for being use by the kernel: they are for user programs only. Also, it is unlikely that is sys v memory sharing works for kernel threads.
Kernel and kernel modules have their own mechanism for interract with user
space. For sharing memory, your kernel module may implement character device and mmap method for it, which maps kernel's allocated memory to user. See example of such mmap implementation in Linux Device Drivers(3d edition), Chapter 15.
#include <WebSocketClient.h>
#include <string.h>
#include <stdlib.h>
#include <Arduino.h>
#include <SocketIOClient.h>
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <WiFi.h>
#define SSID "D"
#define PASS "qwertypoiu"
int keyIndex = 0; // your network key Index number
int status = WL_IDLE_STATUS;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "ec2-52-38-82-235.us-west-2.compute.amazonaws.com:8000";
WebSocketClient client;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial)
{
SoftwareSerial esp8266Module(10,11);
Serial.begin(9600);
Ethernet.begin(mac);
client.connect("update trash");
}
}
void loop() {
// put your main code here, to run repeatedly:
client.monitor();
client.send("56fe4b3368fa1b0edd4b44a1,30");
delay(2000);
}
Above is my code i am unable to compile code .error is serverHandshake' was not declared in this scope . I can't any solution . Any help from your side will be appreciated .
I would like to implement deletion of the default route via WinAPI:
route delete 0.0.0.0
It looks like route is doing via undocumented Nsi* calls. Is there an easier way to do that?
DeleteIpForwardEntry does the trick:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
// Execute as admin
int main()
{
ULONG size = 10000;
PMIB_IPFORWARDTABLE table = (PMIB_IPFORWARDTABLE)malloc(size);
memset(table, 0, size);
GetIpForwardTable(table,&size,true);
for (int i = 0; i < (int) table->dwNumEntries; i++) {
// Default route 0.0.0.0
if(table->table[i].dwForwardDest == 0)
{
DWORD ret = DeleteIpForwardEntry(&table->table[i]);
printf("Ret: %X\n", ret);
break;
}
}
return 0;
}
I'm testing out multicast with the two programs below. The client run well on linux and in wine on two of my machines, but it won't work properly on my windows machine (in Virtualbox).
Strangely, if I start up vlc in windows and open the udp stream, the client program receives the packets - and when I stop vlc, the client goes silent again.
What am I doing wrong?
Here is the the server program:
/*
* server.c - multicast server program.
*/
#include <sys/types.h>
#ifdef WINDOWS
#include <winsock.h>
#include <windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <time.h>
#include <string.h>
#include <stdio.h>
#define HELLO_PORT 5004
#define HELLO_GROUP "224.0.0.1"
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, cnt, numbytes;
struct ip_mreq mreq;
char message[100];
#ifdef WINDOWS
WSADATA wsaData; /* Windows socket DLL structure */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() failed");
return 1;
}
#endif
/* create what looks like an ordinary UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "failed to create socket.\n");
return 1;
}
/* set up destination address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr.sin_port = htons(HELLO_PORT);
/* now just sendto() our destination! */
cnt = 0;
while (1) {
numbytes = sprintf(message, "%d", cnt);
if (sendto(fd, message, numbytes, 0, (struct sockaddr*)&addr,
sizeof(addr)) < 0) {
fprintf(stderr, "sendto failed.\n");
return 1;
}
#ifdef WINDOWS
Sleep(1000);
#else
sleep(1);
#endif
cnt++;
}
return 0;
}
and here's the client program:
/*
* client.c -- client program for udp multicast data.
*/
#include <sys/types.h>
#ifdef WINDOWS
#include <winsock.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <time.h>
#include <string.h>
#include <stdio.h>
#define HELLO_GROUP "224.0.0.1"
#define HELLO_PORT 5004
#define MSGBUFSIZE 256
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
char msgbuf[MSGBUFSIZE];
u_int yes = 1;
#ifdef WINDOWS
WSADATA wsaData; /* Windows socket DLL structure */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() failed");
return 1;
}
#endif
/* create what looks like an ordinary UDP socket */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
fprintf(stderr, "failed to create socket.\n");
return 1;
}
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes)) != 0) {
fprintf(stderr, "failed to reuse port number.\n");
return 1;
}
/* set up destination address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(HELLO_PORT);
/* bind to receive address */
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
fprintf(stderr, "failed to bind socket.\n");
return 1;
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr = inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) != 0) {
fprintf(stderr, "failed to join the multicast group.\n");
return 1;
}
/* now just enter a read-print loop */
while (1) {
addrlen = sizeof(addr);
nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0,
(struct sockaddr*)&addr, &addrlen);
if (nbytes < 0) {
fprintf(stderr, "recfrom failed, %d\n", nbytes);
return 1;
}
msgbuf[nbytes] = '\0';
puts(msgbuf);
}
return 0;
}
Thanks,
Oskar
Ok, so apparently the firewall blocked the packets. Turning it off fixes the issue.