I'm writing a Linux KVM hypervisor for x86 16-bit guests running in real mode. When doing interrupt calls (int ... instruction), I've encountered the KVM_INTERNAL_ERROR_SIMUL_EX error on Linux kernel 3.13.0. The same code is running fine on Linux kernel 3.16.0. Am I missing something? Is there a workaround I can add to my code to make it work with Linux kernel 3.13.0 (and possibly earlier)?
The test guest calls int 0x18 ... int 0x4f, all of which is handled in the hypervisor (C code after KVM_RUN has returned). When it's working correctly, all of the interrupt calls work. On Linux kernel 3.13.0, int 0x21 starts failing (and then int 0x22, int 0x23 and int 0x24 would also fail).
I was trying to write the shortest example C code to demonstrate the problem, here it is:
/* Based on: https://gist.github.com/zserge/d68683f17c68709818f8baab0ded2d15
* Based on: https://gist.githubusercontent.com/zserge/d68683f17c68709818f8baab0ded2d15/raw/b79033254b092ec9121bb891938b27dd128030d7/kvm-host-simple.c
*
* Compile: gcc -ansi -pedantic -s -O2 -W -Wall -o kvm16 kvm16.c && ./kvm16
*
* Expected correct output (e.g. on Linux 3.16.0 compiled for i386 (i686)):
*
* ...
* info: int 0x4f iret to: ...
* info: success, exiting
*
* Failure output (e.g. on Linux 3.13.0 compiled for amd64 (x86_64)):
*
* info: int 0x20 iret to: cs=0x0070 ip=0x0013
* fatal: KVM internal error suberror=2
*
* // Encounter unexpected simultaneous exceptions.
* #define KVM_INTERNAL_ERROR_SIMUL_EX 2
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#define INT_NUM 0x21 /* Also works for INT_NUM == 0x20. */
int main(int argc, char *argv[]) {
int kvm_fd, vm_fd, vcpu_fd;
void *mem;
struct kvm_userspace_memory_region region;
struct kvm_run *run;
struct kvm_regs regs;
struct kvm_sregs sregs;
(void)argc; (void)argv;
if ((kvm_fd = open("/dev/kvm", O_RDWR)) < 0) {
perror("failed to open /dev/kvm");
return 1;
}
if ((vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0)) < 0) {
perror("failed to create vm");
return 1;
}
if ((mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)) == NULL) {
perror("mmap");
return 1;
}
memset(®ion, 0, sizeof(region));
region.slot = 0;
region.guest_phys_addr = 0;
region.memory_size = 0x1000;
region.userspace_addr = (uintptr_t)mem;
if (ioctl(vm_fd, KVM_SET_USER_MEMORY_REGION, ®ion) < 0) {
perror("KVM_SET_USER_MEMORY_REGION");
return 1;
}
{ /* 8086 real mode machine code. */
char *p = (char*)mem + 0x700;
unsigned int_num;
for (int_num = 0; int_num < 0x100; ++int_num) {
*(unsigned short*)((char*)mem + int_num * 4) = int_num; /* Interrupt vector INT_NUM offset := INT_NUM. */
*(unsigned short*)((char*)mem + int_num * 4 + 2) = 0x54; /* Interrupt vector INT_NUM segment := 0x54. */
}
*p++ = (char)0xf4; /* hlt. */
for (int_num = 0x18; int_num < 0x50; ++int_num) {
*p++ = (char)0xcd; /* int int_num. */
*p++ = (char)int_num;
}
*p++ = (char)0xf4;
}
memset((char*)mem + 0x540, '\xf4', 0x100); /* 256 times hlt. Interrupt vectors point here. */
if ((vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0)) < 0) {
perror("KVM_CREATE_VCPU");
return 1;
}
{
int kvm_run_mmap_size = ioctl(kvm_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
if (kvm_run_mmap_size < 0) {
perror("KVM_GET_VCPU_MMAP_SIZE");
return 1;
}
run = (struct kvm_run *)mmap(
NULL, kvm_run_mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu_fd, 0);
if (run == NULL) {
perror("mmap kvm_run");
return 1;
}
}
memset(®s, '\0', sizeof(regs));
if (ioctl(vcpu_fd, KVM_GET_SREGS, &sregs) < 0) {
perror("KVM_GET_SREGS");
return 1;
}
{
int fd = open("kvm16.sregs", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
return 1;
}
if (write(fd, &sregs, sizeof(sregs)) != sizeof(sregs)) {
perror("write");
return 1;
}
if (close(fd) != 0) {
perror("close");
return 1;
}
}
sregs.cs.base = (sregs.cs.selector = 0x70) << 4;
sregs.ds.base = (sregs.ds.selector = sregs.cs.selector) << 4;
sregs.es.base = (sregs.es.selector = sregs.cs.selector) << 4;
sregs.ss.base = (sregs.ss.selector = sregs.cs.selector) << 4;
if (ioctl(vcpu_fd, KVM_GET_REGS, ®s) < 0) {
perror("KVM_GET_REGS");
return 1;
}
regs.rflags = 1 << 1; /* Reserved bit in EFLAGS. Even needed after KVM_GET_REGS. */
regs.rip = 0;
regs.rsp = 0x1000 - 0x700;
if (ioctl(vcpu_fd, KVM_SET_SREGS, &sregs) < 0) {
perror("KVM_SET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_SET_REGS, ®s) < 0) {
perror("KVM_SET_REGS");
return 1;
}
for (;;) {
int ret = ioctl(vcpu_fd, KVM_RUN, 0);
unsigned short cs, ip;
if (ret < 0) {
perror("KVM_RUN");
return 1;
}
if (ioctl(vcpu_fd, KVM_GET_SREGS, &sregs) < 0) {
perror("KVM_GET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_GET_REGS, ®s) < 0) {
perror("KVM_GET_REGS");
return 1;
}
cs = sregs.cs.selector;
ip = regs.rip;
if (run->exit_reason == KVM_EXIT_HLT) {
fprintf(stderr, "info: hlt: cs=0x%04x ip=0x%04x\n", cs, ip - 1);
if (cs == 0x70) {
if (ip != 0 + 1) {
fprintf(stderr, "info: success, exiting\n");
return 0; /* EXIT_SUCCESS after the second `hlt' in the code. */
}
} else if (cs == 0x54) { /* Simulate iret. */
const char *csip_ptr = (const char*)mem + ((unsigned short)sregs.ss.selector << 4) + (unsigned short)regs.rsp;
const unsigned short int_ip = ((const unsigned short*)csip_ptr)[0];
const unsigned short int_cs = ((const unsigned short*)csip_ptr)[1];
const unsigned short int_flags = ((const unsigned short*)csip_ptr)[2];
fprintf(stderr, "info: int 0x%02x iret to: cs=0x%04x ip=0x%04x\n", ip - 1, int_cs, int_ip);
sregs.cs.base = (sregs.cs.selector = int_cs) << 4;
regs.rip = int_ip;
if (int_flags & (1 << 9)) regs.rflags |= (1 << 9); /* Set IF back to 1 if it was 1. */
regs.rsp += 6; /* pop ip, pop cs, popfw . */
if (ioctl(vcpu_fd, KVM_SET_SREGS, &sregs) < 0) {
perror("KVM_SET_SREGS");
return 1;
}
if (ioctl(vcpu_fd, KVM_SET_REGS, ®s) < 0) {
perror("KVM_SET_REGS");
return 1;
}
} else {
fprintf(stderr, "fatal: unexpected hlt: cs=0x%04x ip=0x%04x\n", cs, ip - 1);
return 5;
}
} else if (run->exit_reason == KVM_EXIT_INTERNAL_ERROR) {
fprintf(stderr, "fatal: KVM internal error suberror=%d\n", (unsigned)run->internal.suberror);
return 4;
} else {
fprintf(stderr, "fatal: unexpected KVM exit: exit_reason=%d cs=0x%04x ip=0x%04x\n", run->exit_reason, cs, ip);
return 2;
}
}
}
Related
Code image
Hello DPDK Users,
I was trying to generate the incremental data value of UDP packets via DPDK.
But when I am transmitting it, I verified the same frames in Wireshark.
The data part of packets is changing illogically.
No sequence can be seen in data.
It is optimized the data value which I was wrote. The last value i tried to write was there in all the bytes of payload, not as expected in incremental order.
Can anyone help me, why is this occurring and what could be the easiest way to generate incremental DPDK packets?
The Code is given in the image file above.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include<assert.h>
uint64_t temp1;
uint64_t temp2;
int temp3;
int test_type;
double sec;
time_t start_t,end_t;
double diff_t;
#include<time.h>
#include<signal.h>
#include<linux/kernel.h>
#include <rte_memory.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_ethdev.h>
#include <rte_udp.h>
#include <rte_tcp.h>
#include <rte_ip.h>
#include <rte_arp.h>
#include <rte_icmp.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#define RX_RING_SIZE 2028
#define TX_RING_SIZE 2048
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define UDP_SRC_PORT 6666
#define UDP_DST_PORT 6666
#define TCP_SRC_PORT 6666
#define TCP_DST_PORT 6666
#define IP_DEFTTL 64
#define IP_VERSION 0x40
#define IP_HDRLEN 0x05
#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
#define TX_PACKET_LENGTH 64
#define ETHER_MAX_LEN 1518
#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v)
#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
#else
#define RTE_BE_TO_CPU_16(be_16_v) \
(uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
#define RTE_CPU_TO_BE_16(cpu_16_v) \
(uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
#endif
#define rte_ctrlmbuf_data(m) ((char *)((m)->buf_addr)+(m)->data_off)
// convert a quad-dot IP string to uint32_t IP address
uint32_t string_to_ip(char *s) {
unsigned char a[4];
int rc = sscanf(s, "%d.%d.%d.%d",a+0,a+1,a+2,a+3);
if(rc != 4){
fprintf(stderr, "bad source IP address format. Use like: -s 198.19.111.179\n");
exit(1);
}
return
(uint32_t)(a[0]) << 24 |
(uint32_t)(a[1]) << 16 |
(uint32_t)(a[2]) << 8 |
(uint32_t)(a[3]);
}
// convert six colon separated hex bytes string to uint64_t Ethernet MAC address
uint64_t string_to_mac(char *s) {
unsigned char a[6];
int rc = sscanf(s, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
a + 0, a + 1, a + 2, a + 3, a + 4, a + 5);
if(rc !=6 ){
fprintf(stderr, "bad MAC address format. Use like: -m 0a:38:ca:f6:f3:20\n");
exit(1);
}
return
(uint64_t)(a[0]) << 40 |
(uint64_t)(a[1]) << 32 |
(uint64_t)(a[2]) << 24 |
(uint64_t)(a[3]) << 16 |
(uint64_t)(a[4]) << 8 |
(uint64_t)(a[5]);
}
uint64_t DST_MAC;
uint32_t IP_SRC_ADDR,IP_DST_ADDR;
static const struct rte_eth_conf port_conf_default = {
.rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN }
};
static struct rte_ipv4_hdr pkt_ip_hdr;
static struct rte_udp_hdr pkt_udp_hdr;
struct rte_ether_addr my_addr;
struct rte_mempool *mbuf_pool;
struct rte_data_hdr pkt_data_hdr;
static void setup_pkt_udp_ip_headers(struct rte_ipv4_hdr *ip_hdr,
struct rte_udp_hdr *pudp_hdr,
uint16_t pkt_data_len)
{
uint16_t *ptr16;
uint32_t ip_cksum;
uint16_t pkt_len;
int sizeof_=sizeof(struct rte_udp_hdr);
int sizeof__=sizeof(struct rte_ipv4_hdr);
//initialize udp headers
pkt_len = (uint16_t) (pkt_data_len + sizeof_);
pudp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT);
pudp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT);
pudp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_len);
pudp_hdr->dgram_cksum = 32; // No udp checksum.
//Initialize IP header.
pkt_len = (uint16_t) (pkt_len + sizeof__);
ip_hdr->version_ihl = IP_VHL_DEF;
ip_hdr->type_of_service = 0;
ip_hdr->fragment_offset = 0;
ip_hdr->time_to_live = IP_DEFTTL;
ip_hdr->next_proto_id = IPPROTO_UDP;
ip_hdr->packet_id = 0;
ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len);
ip_hdr->src_addr = rte_cpu_to_be_32(IP_SRC_ADDR);
ip_hdr->dst_addr = rte_cpu_to_be_32(IP_DST_ADDR);
//Compute IP header checksum.
ptr16 = (unaligned_uint16_t*) ip_hdr;
ip_cksum = 0;
ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
ip_cksum += ptr16[4];
ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
//Reduce 32 bit checksum to 16 bits and complement it.
ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
(ip_cksum & 0x0000FFFF);
if (ip_cksum > 65535)
ip_cksum -= 65535;
ip_cksum = (~ip_cksum) & 0x0000FFFF;
if (ip_cksum == 0)
ip_cksum = 0xFFFF;
ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
}
union {
uint64_t as_int;
struct rte_ether_addr as_addr;
} dst_eth_addr;
static void packetsend_withSequence()
{
int counter=1;
int pkt_drop_counter=0;
struct rte_ether_hdr eth_hdr;
struct rte_mbuf *pkt=NULL;
struct rte_mbuf *pkts_burst[1];
struct rte_mbuf *m;
char *data;
char temppacketdata[100];
while(1){
pkt = rte_pktmbuf_alloc(mbuf_pool);
if(pkt == NULL) {printf("trouble at rte_mbuf_raw_alloc\n");}
data = rte_pktmbuf_append(pkt, TX_PACKET_LENGTH);
if(data == NULL ) {printf("trouble at data alloc\n");}
// set up addresses
printf("\n rte_pktmbuf_pkt_len is %d", rte_pktmbuf_pkt_len(pkt));
dst_eth_addr.as_int=rte_cpu_to_be_64(DST_MAC);
rte_ether_addr_copy(&dst_eth_addr,ð_hdr.d_addr);
rte_ether_addr_copy(&my_addr, ð_hdr.s_addr);
eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
memset(temppacketdata,0x0,sizeof(temppacketdata));
memcpy(temppacketdata, ð_hdr,(size_t)sizeof(eth_hdr)); //copy eth header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr), &pkt_ip_hdr,(size_t)sizeof(pkt_ip_hdr)); //copy IP header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr)+(size_t)sizeof(pkt_ip_hdr), &pkt_udp_hdr,(size_t)sizeof(pkt_udp_hdr)); //copy UDP header
memcpy(temppacketdata+(size_t)sizeof(eth_hdr)+(size_t)sizeof(pkt_ip_hdr)+(size_t)sizeof(pkt_udp_hdr), &counter,(size_t)sizeof(counter)); //copy int data
memcpy(data,temppacketdata,rte_pktmbuf_pkt_len(pkt));
pkts_burst[0] = pkt;
const uint16_t nb_tx = rte_eth_tx_burst(0, 0, pkts_burst,1);
if (unlikely(nb_tx < 1))
{
pkt_drop_counter++;
rte_pktmbuf_free(pkt); // This frees chained segs
}
else{
counter++;
printf("%d",nb_tx);
}
if(counter > 1000)
break;
}
printf(" pkt_drop_counter = %d counter =%d",pkt_drop_counter,counter);
}
// Initialize Port
static inline int
port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
int retval;
uint16_t q;
struct rte_eth_dev_info dev_info;
struct rte_eth_txconf txconf;
if (!rte_eth_dev_is_valid_port(port))
return -1;
rte_eth_dev_info_get(port, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
/* Configure the Ethernet device. */
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0)
return retval;
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
//Allocate and set up 1 TX queue
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
return retval;
}
/* Allocate and set up 1 RX queue per Ethernet port. */
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
/* Start the Ethernet port. */
retval = rte_eth_dev_start(port);
if (retval < 0)
return retval;
/* get the port MAC address. */
rte_eth_macaddr_get(port, &my_addr);
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
port,
my_addr.addr_bytes[0], my_addr.addr_bytes[1],
my_addr.addr_bytes[2], my_addr.addr_bytes[3],
my_addr.addr_bytes[4], my_addr.addr_bytes[5]);
return 0;
}
int main(int argc, char **argv)
{
int ret,c;
uint16_t pkt_data_len;
int mac_flag=0,ip_src_flag=0,ip_dst_flag=0;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
argc -= ret;
argv += ret;
while ((c = getopt(argc, argv, "m:s:d:h")) != -1)
switch(c) {
case 'm':
// note, not quite sure why last two bytes are zero, but that is how DPDK likes it
DST_MAC=0ULL;
DST_MAC=string_to_mac(optarg)<<16;
mac_flag=1;
break;
case 's':
IP_SRC_ADDR=string_to_ip(optarg);
ip_src_flag=1;
break;
case 'd':
IP_DST_ADDR=string_to_ip(optarg);
ip_dst_flag=1;
break;
case 'h':
printf("usage -- -m [dst MAC] -s [src IP] -d [dst IP]\n");
exit(0);
break;
}
if(mac_flag==0) {
fprintf(stderr, "missing -m for destination MAC adress\n");
exit(1);
}
if(ip_src_flag==0) {
fprintf(stderr, "missing -s for IP source adress\n");
exit(1);
}
if(ip_dst_flag==0) {
fprintf(stderr, "missing -d for IP destination adress\n");
exit(1);
}
/* Creates a new mempool in memory to hold the mbufs. */
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
// initialize port 0
if (port_init(0,mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port 0\n");
/* Initialize all ports. */
if (port_init(1, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n",
1);
pkt_data_len = (uint16_t) (TX_PACKET_LENGTH - (sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_udp_hdr)));
setup_pkt_udp_ip_headers(&pkt_ip_hdr, &pkt_udp_hdr, pkt_data_len);
packetsend_withSequence();
// send_packet();
return(0);
}
I am unable to interface mcp 3008 with beaglebone green.trying to set communication in mode 0(CPOL =0 CPHA=0),the built in frequency in dts is set to 1Mhz.
things I have tried
1.enable device tree BB-SPI0-MCP3008-00A0.dts
on execution of
ls -al /dev/spidev1.*
I got
crw-rw---- 1 root spi 153, 0 Oct 7 16:40 /dev/spidev1.1
2.on execution of
cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pingroups
group: pinmux_bb_spi0_pins pin 84 (PIN84) pin 85 (PIN85) pin 86 (PIN86) pin 87 (PIN87)
My reference code is as follow
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
static const char *DEVICE = "/dev/spidev1.1";
static uint8_t MODE = SPI_MODE_0;
static uint8_t BITS = 8;
static uint32_t CLOCK = 1000000;
static uint16_t DELAY = 5;
/* * Ensure all settings are correct for the ADC */
static int prepare(int fd)
{
if (ioctl(fd, SPI_IOC_WR_MODE, &MODE) == -1)
{
perror("Can't set MODE"); return -1;
}
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &BITS) == -1)
{
perror("Can't set number of BITS");
return -1;
}
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set write CLOCK");
return -1;
}
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &CLOCK) == -1)
{
perror("Can't set read CLOCK"); return -1;
}
return 0;
}
/* * (SGL/DIF = 0, D2=D1=D0=0) */
uint8_t control_bits_differential(uint8_t channel)
{
return (channel & 7) << 4;
}
/* * (SGL/DIF = 1, D2=D1=D0=0) */
uint8_t control_bits(uint8_t channel)
{
return 0x8 | control_bits_differential(channel);
}
/* * Given a prep'd descriptor, and an ADC channel, fetch the * raw ADC
value for the given channel. */
int readadc(int fd, uint8_t channel)
{
uint8_t tx[] = {1, control_bits(channel), 0
};
uint8_t rx[3]={0,0,0};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = DELAY,
.speed_hz = CLOCK,
.bits_per_word = BITS, };
if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == 1)
{
perror("IO Error");
abort();
}
return ((rx[1] << 8) & 0x300) | (rx[2] & 0xFF);
}
int main(int argc, char **argv)
{
int fd = open(DEVICE, O_RDWR);
if (fd <= 0)
{
printf("Device %s not found\n", DEVICE);
return -1;
}
if (prepare(fd) == -1)
{ return -1; }
uint8_t i,radc=0;
for(i = 0;i < 8;i++)
{ printf("Channel %d: %d\n", i + 1, readadc(fd, i)); }
close(fd);
return 0;
}
after executing this code I am getting 1023 count for any applied voltage,where I am expecting count 0 for 0 input voltage and so on .
Can anybody please help me? can you tell me where I am doing wrong?what are the other things I have to consider while using SPI on beaglebone?any kind of help will be greatly appreciated!
solved it as suggested from other forum it was hardware related thing.I have to put 0.1uf capacitor between vcc and gnd,where analog ground and digital ground were common.
I am trying to create a modbus master slave model. I have written modbus slave using pymodbus and modbus master is using c libmodbus.
Slave is having a bunch of register set and register 0 is having value as
register 0, number of register 2, type hex, value 45565345
register 2, number of register 4, type hex, value 10002
I am using modbus over TCP
Below is the c code
/*
* Copyright © 2008-2014 Stéphane Raimbault <stephane.raimbault#gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus.h>
#include "unit-test.h"
const int EXCEPTION_RC = 2;
enum {
TCP,
TCP_PI,
RTU
};
int test_server(modbus_t *ctx, int use_backend);
int send_crafted_request(modbus_t *ctx, int function,
uint8_t *req, int req_size,
uint16_t max_value, uint16_t bytes,
int backend_length, int backend_offset);
int equal_dword(uint16_t *tab_reg, const uint32_t value);
#define BUG_REPORT(_cond, _format, _args ...) \
printf("\nLine %d: assertion error for '%s': " _format "\n", __LINE__, # _cond, ## _args)
#define ASSERT_TRUE(_cond, _format, __args...) { \
if (_cond) { \
printf("OK\n"); \
} else { \
BUG_REPORT(_cond, _format, ## __args); \
goto close; \
} \
};
int equal_dword(uint16_t *tab_reg, const uint32_t value) {
return ((tab_reg[0] == (value >> 16)) && (tab_reg[1] == (value & 0xFFFF)));
}
int main(int argc, char *argv[])
{
const int NB_REPORT_SLAVE_ID = 10;
uint8_t *tab_rp_bits = NULL;
uint16_t *tab_rp_registers = NULL;
uint16_t *tab_rp_registers_bad = NULL;
modbus_t *ctx = NULL;
int i;
uint8_t value;
int nb_points;
int rc;
float real;
uint32_t old_response_to_sec;
uint32_t old_response_to_usec;
uint32_t new_response_to_sec;
uint32_t new_response_to_usec;
uint32_t old_byte_to_sec;
uint32_t old_byte_to_usec;
int use_backend;
int success = FALSE;
int old_slave;
if (argc > 1) {
if (strcmp(argv[1], "tcp") == 0) {
use_backend = TCP;
} else if (strcmp(argv[1], "tcppi") == 0) {
use_backend = TCP_PI;
} else if (strcmp(argv[1], "rtu") == 0) {
use_backend = RTU;
} else {
printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus client for unit testing\n\n", argv[0]);
exit(1);
}
} else {
/* By default */
use_backend = TCP;
}
if (use_backend == TCP) {
ctx = modbus_new_tcp("127.0.0.1", 1520);
} else if (use_backend == TCP_PI) {
ctx = modbus_new_tcp_pi("::1", "1520");
} else {
ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1);
}
if (ctx == NULL) {
fprintf(stderr, "Unable to allocate libmodbus context\n");
return -1;
}
modbus_set_debug(ctx, TRUE);
modbus_set_error_recovery(ctx,
MODBUS_ERROR_RECOVERY_LINK |
MODBUS_ERROR_RECOVERY_PROTOCOL);
if (use_backend == RTU) {
modbus_set_slave(ctx, SERVER_ID);
}
modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
modbus_get_response_timeout(ctx, &new_response_to_sec, &new_response_to_usec);
printf("** UNIT TESTING **\n");
rc = modbus_read_registers(ctx, 0x02,
2, tab_rp_registers);
printf(" value %d" , tab_rp_registers[0]);
modbus_close(ctx);
modbus_free(ctx);
ctx = NULL;
close:
/* Free the memory */
free(tab_rp_bits);
free(tab_rp_registers);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return (success) ? 0 : -1;
}
/* Send crafted requests to test server resilience
and ensure proper exceptions are returned. */
int test_server(modbus_t *ctx, int use_backend)
{
int rc;
int i;
/* Read requests */
const int READ_RAW_REQ_LEN = 6;
const int slave = (use_backend == RTU) ? SERVER_ID : MODBUS_TCP_SLAVE;
uint8_t read_raw_req[] = {
slave,
/* function, address, 5 values */
MODBUS_FC_READ_HOLDING_REGISTERS,
UT_REGISTERS_ADDRESS >> 8, UT_REGISTERS_ADDRESS & 0xFF,
0x0, 0x05
};
/* Write and read registers request */
const int RW_RAW_REQ_LEN = 13;
uint8_t rw_raw_req[] = {
slave,
/* function, addr to read, nb to read */
MODBUS_FC_WRITE_AND_READ_REGISTERS,
/* Read */
UT_REGISTERS_ADDRESS >> 8, UT_REGISTERS_ADDRESS & 0xFF,
(MODBUS_MAX_WR_READ_REGISTERS + 1) >> 8,
(MODBUS_MAX_WR_READ_REGISTERS + 1) & 0xFF,
/* Write */
0, 0,
0, 1,
/* Write byte count */
1 * 2,
/* One data to write... */
0x12, 0x34
};
const int WRITE_RAW_REQ_LEN = 13;
uint8_t write_raw_req[] = {
slave,
/* function will be set in the loop */
MODBUS_FC_WRITE_MULTIPLE_REGISTERS,
/* Address */
UT_REGISTERS_ADDRESS >> 8, UT_REGISTERS_ADDRESS & 0xFF,
/* 3 values, 6 bytes */
0x00, 0x03, 0x06,
/* Dummy data to write */
0x02, 0x2B, 0x00, 0x01, 0x00, 0x64
};
const int INVALID_FC = 0x42;
const int INVALID_FC_REQ_LEN = 6;
uint8_t invalid_fc_raw_req[] = {
slave, 0x42, 0x00, 0x00, 0x00, 0x00
};
int req_length;
uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
int tab_read_function[] = {
MODBUS_FC_READ_COILS,
MODBUS_FC_READ_DISCRETE_INPUTS,
MODBUS_FC_READ_HOLDING_REGISTERS,
MODBUS_FC_READ_INPUT_REGISTERS
};
int tab_read_nb_max[] = {
MODBUS_MAX_READ_BITS + 1,
MODBUS_MAX_READ_BITS + 1,
MODBUS_MAX_READ_REGISTERS + 1,
MODBUS_MAX_READ_REGISTERS + 1
};
int backend_length;
int backend_offset;
if (use_backend == RTU) {
backend_length = 3;
backend_offset = 1;
} else {
backend_length = 7;
backend_offset = 7;
}
printf("\nTEST RAW REQUESTS:\n");
uint32_t old_response_to_sec;
uint32_t old_response_to_usec;
/* This requests can generate flushes server side so we need a higher
* response timeout than the server. The server uses the defined response
* timeout to sleep before flushing.
* The old timeouts are restored at the end.
*/
modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);
modbus_set_response_timeout(ctx, 0, 600000);
req_length = modbus_send_raw_request(ctx, read_raw_req, READ_RAW_REQ_LEN);
printf("* modbus_send_raw_request: ");
ASSERT_TRUE(req_length == (backend_length + 5), "FAILED (%d)\n", req_length);
printf("* modbus_receive_confirmation: ");
rc = modbus_receive_confirmation(ctx, rsp);
ASSERT_TRUE(rc == (backend_length + 12), "FAILED (%d)\n", rc);
/* Try to read more values than a response could hold for all data
types. */
for (i=0; i<4; i++) {
rc = send_crafted_request(ctx, tab_read_function[i],
read_raw_req, READ_RAW_REQ_LEN,
tab_read_nb_max[i], 0,
backend_length, backend_offset);
if (rc == -1)
goto close;
}
/* Modbus write and read multiple registers */
rc = send_crafted_request(ctx, MODBUS_FC_WRITE_AND_READ_REGISTERS,
rw_raw_req, RW_RAW_REQ_LEN,
MODBUS_MAX_WR_READ_REGISTERS + 1, 0,
backend_length, backend_offset);
if (rc == -1)
goto close;
/* Modbus write multiple registers with large number of values but a set a
small number of bytes in requests (not nb * 2 as usual). */
rc = send_crafted_request(ctx, MODBUS_FC_WRITE_MULTIPLE_REGISTERS,
write_raw_req, WRITE_RAW_REQ_LEN,
MODBUS_MAX_WRITE_REGISTERS + 1, 6,
backend_length, backend_offset);
if (rc == -1)
goto close;
rc = send_crafted_request(ctx, MODBUS_FC_WRITE_MULTIPLE_COILS,
write_raw_req, WRITE_RAW_REQ_LEN,
MODBUS_MAX_WRITE_BITS + 1, 6,
backend_length, backend_offset);
if (rc == -1)
goto close;
/* Test invalid function code */
modbus_send_raw_request(ctx, invalid_fc_raw_req, INVALID_FC_REQ_LEN * sizeof(uint8_t));
rc = modbus_receive_confirmation(ctx, rsp);
printf("Return an exception on unknown function code: ");
ASSERT_TRUE(rc == (backend_length + EXCEPTION_RC) &&
rsp[backend_offset] == (0x80 + INVALID_FC), "")
modbus_set_response_timeout(ctx, old_response_to_sec, old_response_to_usec);
return 0;
close:
modbus_set_response_timeout(ctx, old_response_to_sec, old_response_to_usec);
return -1;
}
int send_crafted_request(modbus_t *ctx, int function,
uint8_t *req, int req_len,
uint16_t max_value, uint16_t bytes,
int backend_length, int backend_offset)
{
uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
int j;
for (j=0; j<2; j++) {
int rc;
req[1] = function;
if (j == 0) {
/* Try to read or write zero values on first iteration */
req[4] = 0x00;
req[5] = 0x00;
if (bytes) {
/* Write query */
req[6] = 0x00;
}
} else {
/* Try to read or write max values + 1 on second iteration */
req[4] = (max_value >> 8) & 0xFF;
req[5] = max_value & 0xFF;
if (bytes) {
/* Write query (nb values * 2 to convert in bytes for registers) */
req[6] = bytes;
}
}
modbus_send_raw_request(ctx, req, req_len * sizeof(uint8_t));
if (j == 0) {
printf("* try function 0x%X: %s 0 values: ", function, bytes ? "write": "read");
} else {
printf("* try function 0x%X: %s %d values: ", function, bytes ? "write": "read",
max_value);
}
rc = modbus_receive_confirmation(ctx, rsp);
ASSERT_TRUE(rc == (backend_length + EXCEPTION_RC) &&
rsp[backend_offset] == (0x80 + function) &&
rsp[backend_offset + 1] == MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, "");
}
return 0;
close:
return -1;
}
I am getting below output from modbus master
Connecting to 127.0.0.1:1520
** UNIT TESTING **
[00][01][00][00][00][06][FF][03][00][02][00][02]
Waiting for a confirmation...
<00><01><00><00><00><07><FF><03><04><00><01><00><02>
Segmentation fault (core dumped)
Output on modbus slave
DEBUG:pymodbus.server.async:Client Connected [IPv4Address(type='TCP', host='127.0.0.1', port=1520)]
DEBUG:pymodbus.server.async:Data Received: 0x0 0x1 0x0 0x0 0x0 0x6 0xff 0x3 0x0 0x2 0x0 0x2
DEBUG:pymodbus.framer.socket_framer:Processing: 0x0 0x1 0x0 0x0 0x0 0x6 0xff 0x3 0x0 0x2 0x0 0x2
DEBUG:pymodbus.factory:Factory Request[3]
DEBUG:pymodbus.datastore.context:validate[3] 3:2
DEBUG:pymodbus.datastore.context:getValues[3] 3:2
DEBUG:pymodbus.datastore.context:xxxxxxxxxxxxxxxxxxxxxxxxx
DEBUG:pymodbus.datastore.context:[1, 2]
DEBUG:pymodbus.server.async:send: 000100000007ff030400010002
DEBUG:pymodbus.server.async:Client Disconnected: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
I am trying to retrieve value of the register. Not sure why I am not getting the value
I have never used this stack but RTFM says:
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
...
You must take care to allocate enough memory to store the results in dest (at least nb * sizeof(uint16_t)).
But tab_rp_registers is set to NULL and never allocated.
As a result of large research, I found this source code for STM32f1 this link and I changed it for STM32f3. And the build and install to my STM32. My ethernet cable connect between my computer and enc28j60 module. If I debugging this code my code stack in main.c and while loop:
while (1)
{
eMBPoll();
led_poll();
/* 从网络设备读取一个IP包,返回数据长度 */
uip_len = tapdev_read();
/* 收到数据 */
**if (uip_len > 0)**
{
/* 处理IP数据包 */
if (BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();
uip_input();
if (uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
/* 处理ARP报文 */
else if (BUF->type == htons(UIP_ETHTYPE_ARP))
{
uip_arp_arpin();
if (uip_len > 0)
{
tapdev_send();
}
}
}
I stuck if (uip_len > 0) line because uip_len return 0 for this line:
(My code same as bellow github link so i dont share all of code )
enc28j_60.c in the unsigned int enc28j60_packet_receive(unsigned char *packet, unsigned int maxlen) function:
unsigned int enc28j60_packet_receive(unsigned char *packet, unsigned int maxlen)
{
unsigned int rxstat;
unsigned int len;
if (enc28_read(EPKTCNT) == 0)
{
return (0);
}
enc28_write(ERDPTL, (next_pack_ptr));
enc28_write(ERDPTH, (next_pack_ptr) >> 8);
next_pack_ptr = enc28_readOp(ENC28J60_READ_BUF_MEM, 0);
next_pack_ptr |= enc28_readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
len = enc28_readOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28_readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
len -= 4;
rxstat = enc28_readOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28_readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
if (len > maxlen - 1)
{
len = maxlen - 1;
}
**if ((rxstat & 0x80) == 0)
{
GPIO_SetBits(GPIOE, GPIO_Pin_9);
len = 0;
}**
else
{
des_enc28_readBuffer(packet, len);
}
enc28_write(ERXRDPTL, (next_pack_ptr));
enc28_write(ERXRDPTH, (next_pack_ptr) >> 8);
enc28_writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
return (len);
}
Why is the rxstat & 0x80) == 0? I do not understand.
According to the ENC28J60 datasheet, it seems like RXSTAT flag should be at bit 12:
I am not exactly sure if des_enc28_readOp(ENC28J60_READ_BUF_MEM, 0) is reading the right thing, but I believe you should have something like:
unsigned PHSTAT2 = des_enc28_readOp(ENC28J60_READ_BUF_MEM, 0);
PHSTAT2 |= des_enc28_readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
unsigned RXSTAT = (PHSTAT2 & 0x1000) != 0;
if (RXSTAT)
{
// RXSTAT flag is set
des_enc28_readBuffer(packet, len);
}
else
{
...
}
I would also dump the values of this register to a log or serial port, to make sure you understand what its contents actually are:
// I noticed serialprint in your other question, so I am presuming this is your log func
serialprint("PHSTAT2 = 0x%04x\n", PHSTAT2);
Hey I am trying to write a user space application to move some data to an I2C for an embedded system running PetaLinux, an operating system for embedded Linux, although I do not think that is what is affecting the issue. I am getting a Connection timeout and a segmentation fault.
The function has macros that direct it to write to the first I2C bus. I specify the data that I want to write in main and pass it to i2c_write, which then passes it to i2c_ioctl_write.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
#define REG_ADDR 0x00
int i2c_ioctl_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2c_ioctl_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(1 + 2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
printf("\tBuffer Allocation Successful...\n");
buf[j ++] = regaddr;
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
printf("\tBuffer Setup Successful...\n");
struct i2c_msg messages[] = {
{
.addr = dev,
.buf = buf,
.len = sizeof(buf) / sizeof(buf[0]),
},
};
printf("\tSetup I2C Messages...\n");
struct i2c_rdwr_ioctl_data payload = {
.msgs = messages,
.nmsgs = sizeof(messages) / sizeof(messages[0]),
};
printf("\tSetup I2C IOCTL Payload...\n");
ret = ioctl(fd, I2C_RDWR, &payload);
printf("\tWrote with IOCTL...\n");
if (ret < 0) {
ret = -errno;
}
free (buf);
return ret;
}
int i2c_ioctl_smbus_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2c_ioctl_smbus_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
struct i2c_smbus_ioctl_data payload = {
.read_write = I2C_SMBUS_WRITE,
.size = I2C_SMBUS_WORD_DATA,
.command = regaddr,
.data = (void *) buf,
};
ret = ioctl (fd, I2C_SLAVE_FORCE, dev);
if (ret < 0)
{
ret = -errno;
goto exit;
}
ret = ioctl (fd, I2C_SMBUS, &payload);
if (ret < 0)
{
ret = -errno;
goto exit;
}
exit:
free(buf);
return ret;
}
int i2c_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2x_write\n");
uint64_t funcs;
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
return -errno;
}
if (funcs & I2C_FUNC_I2C) {
return i2c_ioctl_write (fd, dev, regaddr, data);
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
return i2c_ioctl_smbus_write (fd, dev, regaddr, data);
} else {
return -ENOSYS;
}
}
int main (int argc, char *argv[])
{
printf("main\n");
uint8_t regaddr;
int fd;
int ret = 0;
uint16_t data[] = {1, 2, 4};
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
ret = i2c_write(fd, I2C_DEVICE, REG_ADDR, data);
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
free(data);
return ret;
}
When I run the program on QEMU I get the following output:
main
i2x_write
i2c_ioctl_write
Buffer Allocation Successful...
Buffer Setup Successful...
Setup I2C Messages
Setup I2C IOCTL Payload
cdns-i2c e0004000.i2c: timeout waiting on completion
Wrote with IOCTL
Connection timed out.
Segmentation fault
I assume it is failing on the line
ret = ioctl(fd, I2C_RDWR, &payload);
but I am not sure why. Was the payload constructed improperly?
Update: Here is the current code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int main (int argc, char *argv[])
{
int fd;
int ret = 0;
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
uint64_t funcs;
int addr = 0X00;
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
printf("Cannot setup as slave");
exit(1);
}
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
printf("ioctl failed");
return -errno;
}
printf("funcs & I2C_FUNC_I2C: %llu\n", funcs & I2C_FUNC_I2C);
printf("funcs & I2C_FUNC_SMBUS_WORD_DATA: %llu\n", funcs & I2C_FUNC_SMBUS_WORD_DATA);
__u8 reg = 0x10;
__s32 res;
if (funcs & I2C_FUNC_I2C) {
char buf[10];
printf("Attempting to write to I2C bus via I2C protocol...\n");
buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
int bytes_written = write(fd, buf, 3);
if(bytes_written != 3) {
printf("Wrote %d bytes", bytes_written);
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
char buf2[10];
printf("Attempting to read from I2C bus via I2C protocol...\n");
if(read(fd, buf2, 1) != 1) {
printf("\tFailed to do I2C read from Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", buf[0]);
printf("\t\tRead value: %c", buf2[0]);
}
return 0;
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
printf("Attempting to write to I2C bus via SMBus protocol...\n");
//res = i2c_smbus_write_word_data(fd, REG_ADDR, 0x6543);
res = 1;
if(res < 0) {
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
//res = i2c_smbus_read_word_data(fd, REG_ADDR);
if(res < 0) {
printf("\tFailed to read from I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", 0x6543);
printf("\t\tRead value: %c", res);
}
} else {
printf("Cannot write to I2C");
return -ENOSYS;
}
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
return ret;
}
I was able to get rid of the seg fault by removing free(), so thanks there. I have pinpointed the exact issue of the timeout which occurs in the Cadence I2C Driver here:
https://github.com/Xilinx/linux-xlnx/blob/3f3c7b60919d56119a68813998d3005bca501a40/drivers/i2c/busses/i2c-cadence.c#L825
which is still occurring.
As mentioned, there is probably some issue with the way I am writing to slave causing the slave to not send ACK, resulting in a timeout. I am not sure which registers I will need to write what to. I have a feeling the I2C_DEVICE macro and addr and reg variables will need to be changed.
cdns-i2c e0004000.i2c: timeout waiting on completion
It seems that i2c driver (cdns-i2s) doesnt recieves the acknowledgment from the slave. It may occur as you are using I2C-slave address as 0x00 which is a general call address. While using general call address the second byte that is sent has a special purpose which is mentioned in the i2c-specification (section 3.1.13).
If you use general call address you need to follow the specification or else Try using the exact i2c slave address instead of general call address(0x00).