i2c on silicon image c8051f32x (using USBXpress) - image

I have the I2C (SMBus) working properly in this uC and have a VB GUI which can communicate over USB (using USBXpress) and do I2C transactions from the uC to a separate IC. The problem is that I am having the uC poll a register on the IC every 1s. When I do an asynchronous GUI I2C transaction, every once in a while, I believe it collides with the polling I2C transaction and all the I2C data gets shifted at the GUI (i.e., register 0x00's data shows up on register 0x01) . The I2C data in the IC looks correct (by spying on the I2C bus with a LA). What exactly is happening and how can I fix this?

If the polling between the uC and I2C is happening over the same I2C bus as that used by your GUI app then you need to make sure that access to the I2C is controlled such that one transaction completes before the other is allowed to begin. Maybe you are doing this already but this is not clear from the question.
Also, posting some code or pseudo code of the uC code might help.

Related

Linux I2C custom message frame sending

Is it possible to send out a custom message frame on I2C dev from Linux? I am using an i.MX7D board and i would like to use "/dev/i2c-0" device like a simple "serial tty" to "write(fd, bytes, count)". My goal is to send out a single byte for example 0xAB on I2C without any specific slave address and without automatic stop/start bit inserting in my frame.
So i like to make my full custom I2C frame then send it out from Linux. Is it possible, is there any user-space programing techniques in C/C++, Python or any API for it in Linux?
No you can't, because this is limited by the hardware, if you are using the I2c interface, the hardware will limit what you can do.
One way to try is that you can use gpio to simulate i2c or any interface you want to. Many chips support setting the i2c interface to gpio, then you simulate a clock with one gpio, and simulate high and low level with another gpio.
But I don't recommend it, because if you don't follow the i2c protocol, you can't communicate with other i2c devices
Connect two GPIO lines to the I2C bus in addition to the I2C interface. Normally, these will stay tri-stated. When you need to send the magic byte, enable them to send clock and data, then disable them. These won't interfere with I2C, which only drives the bus when transmitting.

How and where is i2c protocol implemented for master send/receive in linux kernel tree?

Apologies for such a generic title but couldn't think of any better.
I am trying to understand where in drivers/i2c/ is the protocol sequence of sending START, ADDR, DATA, STOP bit sequence implemented, as per the protocol. I want to verify the protocol for send/receive in the driver code, that's all the objective here.
I am using Hikey 620 as a reference which has DesignWare's I2C controller. Below is the registration code I can see (elixir):
static const struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
If I trace the i2c_dw_xfer function recursively, the last call I could see are readl_relaxed, writel_relaxed in i2c_dw_xfer_init() (elixir).
Beyond this is all assembly. Are these readl/writel the actual sequence of start/data/stop byte sequences? Or am I understanding it totally wrong?
In that case, please help and point me to the correct flow. If what I got is correct, is there some simpler controller code which has a cleaner implementation and can be used as reference.
The protocol itself is not part of the driver code. What the dw_{readl/writel} functions do by calling readl/writel is write to the registers of the I2C peripheral of the concerned SoC. It is the job of the I2C controller on the SoC to then generate the correct I2C signalling. You can see by going through the datasheet that something like DW_IC_CON is a register offset in the I2C peripheral memory map.

bypassing tty layer and copy to user

I would like to copy data to user space from kernel module which receives data from serial port and transfers it to DMA, which in turn forwards the data to tty layer and finally to user space.
the current flow is
serial driver FIFO--> DMA-->TTY layer -->User space (the data to tty layer is emptied from DMA upon expiration of timer)
What I want to achieve is
serial driver FIFO-->DMA-->user space. (I am OK with using timer to send the data to user space, if there is a better way let me know)
Also the kernel module handling the serialFIFO->DMA is not a character device.
I would like to bypass tty layer completely. what is the best way to achieve so?
Any pointers/code snippet would be appreciated.
In >=3.10.5 the "serial FIFO" that you refer to is called a uart_port. These are defined in drivers/tty/serial.
I assume that what you want to do is to copy the driver for your UART to a new file, then instead of using uart_insert_char to insert characters from the UART RX FIFO, you want to insert the characters into a buffer that you can access from user space.
The way to do this is to create a second driver, a misc class device driver that has file operations, including mmap, and that allocates kernel memory that the driver's mmap file operation function associates with the userspace mapped memory. There is a good example of code for this written by Maxime Ripard. This example was written for a FIQ handled device, but you can use just the probe routine's dma_zalloc_coherent call and the mmap routine, with it's call to remap_pfn_range, to do the trick, that is, to associate a user space mmap on the misc device file with the alloc'ed memory.
You need to connect the memory that you allocated in your misc driver to the buffer that you write to in your UART driver using either a global void pointer, or else by using an exported symbol, if your misc driver is a module. Initialize the pointer to a known invalid value in the UART driver and test it to make sure the misc driver has assigned it before you try to insert characters to the address to which it points.
Note that you can't add an mmap function to the UART driver directly because the UART driver class does not support an mmap file operation. It only supports the operations defined in the include/linux/serial_core.h struct uart_ops.
Admittedly this is a cumbersome solution - two device drivers, but the alternative is to write a new device class, a UART device that has an mmap operation, and that would be a lot of work compared with the above solution although it would be elegant. No one has done this to date because as Jonathan Corbet say's "...not every device lends itself to the mmap abstraction; it makes no sense, for instance, for serial ports and other stream-oriented devices", though this is exactly what you are asking for.
I implemented this solution for a polling mode UART driver based on the mxs-auart.c code and Maxime's example. It was non-trivial effort but mostly because I am using a FIQ handler for the polling timer. You should allow two to three weeks to get the whole thing up and running.
The DMA aspect of your question depends on whether the UART supports DMA transfer mode. If so, then you should be able to set it using the serial flags. The i.MX28's PrimeCell auarts support DMA transfer but for my application there was no advantage over simply reading bytes directly from the UART RX FIFO.

PIC16F88, portb.bit6, and I2C

I am having an odd problem with my PIC16F88. I have an EEPROM connected thru I2C and it works flawlessly until I write to portb.bit6. From that point on, I start getting garbage from my EEPROM. I tried explicitly disabling Timer 1, which uses portb.6 for oscillator-out but that did not help. I tried cutting the trace from the PIC pin (pin 12) so that there is nothing physically connected to it and that did not help. My C code is simple, either portb.6 = 0 or portb.6 = 1. Either way, reading the EEPROM thru I2C fails forever more. The generated ASM code looks fine. The problem occurs on every board that I have tried it on, so it is not localized to one PCB. I am mystified. Any suggestions?
It turns out that it is necessary to write a zero bit to the SCL and SDA pins every time before writing to any bit in portb. FWIW, I was bit-banging rather than using the SSP peripheral of the PIC16F88 for the I2C communicaitons. Thanks to the people on the Yahoo group, Electronics_101, for figuring out this puzzle.

Creating new task in FreeRTOS for USART reception

I am using EVK1105 development board with AVR Studio 5 as development IDE for my AVR project.
I am using FreeRTOS in it. I have 3 USART ports on this board. One external module is connected to my AVR32 board via USART-RS232 mode. It sends me continuous serial data to my board on USART0 with 19230 baudrate, 7-databits, odd parity, stopbit-1 and normal-channel mode. I created a new task for this purpose. After each 9 data bytes it sends '\n' and '\r'. So in my task I keep on collecting the 9 databytes in a string buffer and then transmit it on USART1. I am using polling method to collect data from USAR0 which is receiving port. But I am facing problem in receiving data. I don't know if its timing issue or something or the scheduler switches the task while collects the data. But I don't get the required data.
Following are things I have already checked as troubleshooting
1. Connected my external module to my PC hyper-terminal which gives me perfect result.
2. Implemented the same thing of using receiving from USART0 and whatever received is transmitted to USART1 as without FreeRTOS. Its works fine.
Please suggest some idea what may be wrong. I am using a queue to communicate between Tx and Rx task to pass the string buffer from USART0 to USART1. Is it problem in handling queue? How can I troubleshoot the queue?
I am using a delay of 50ms in my infinite task loop in Rx Task. Can it create a problem? If I don't use any delay the OS crashes. Please suggest some good practices to create a new task in FreeRTOS so that I will not get any timing issue.
For such a use case, I would not use a polling method with 50ms delay to retrieve data from UART peripheral. You can easily lose received data depending on the system load and UART reception buffer size.
At least use an interrupt on UART data reception that copies every received byte into a local buffer that will be read by your TX thread.
You can have an even better solution using a DMA channel to receive your data frame and be notified when 9 bytes have been received. I don't know if your AVR device has a DMA peripheral or not.
Are you still working on this? The statement of your problem is vague, but there I have several suggestions/leading questions.
1) You may want some documents to see what the registers are
Get the giant datasheet pdfs at
http://www.atmel.com/dyn/products/product_docs.asp?category_id=163&family_id=607&subfamily_id=2138&part_id=4117
2) In this and an earlier post you state that you have, in some cases, been able to RX data. You will need to find the USART HW initialization code from those example projects and get them into the freeRTOS example project. In particular calls to
gpio_enable_module() with {AVR32_USART0_RXD_0_0_PIN, AVR32_USART0_RXD_0_0_FUNCTION}
To connect to USART to CPU
and i believe
InitRs232()
Just doing this requires poking around a lot of code - there's alot of dependencies.
2) What function are you calling to retrieve data from USART0? 19kbaud is approximately 2000bytes/sec or 1 byte/0.5ms, so 50ms polling is not nearly enough. I'd suggest that your RX task poll continuously (never sleep explicitly) but at a lower priority than the TX task.
3) Concentrate on debugging the RX task at the call to retrieve data. Use the debugger to look at the hardware registers for the usart. In particular
USART0 cr register AVR32_USART_CR_RXEN_MASK should be set to enable RX
USART0 csr register AVR32_USART_CSR_RXRDY_MASK will indicate if there is new data there
You can also check the overlow flag to see if you have missed some data.
When the read of USART0 rhr occurs it should be a byte that you sent.
If you are still working on this I can look into this a bit more.

Resources