I want to implement a serial loopback driver code in 8250.c found in /drivers/tty/serial/8250.c as found in linux-3.6.1 kernel.
I do not want to use the hardware loopback(i.e by shorting pin 2(tx) and 3(rx) of the standard serial port), instead I want to modify the 8250.c driver such that, the data from user space will travel from the "serial8250_tx_char" function directly to the "serial8250_rx_char" without going to the hardware, i.e I want to receive what is transmitted?
One possible implementation would be to put the transmission circular buffer data into the tty flip buffer, and then push this data up to the tty core so that the user space can receive it?
I want to know how to do it in the code. We can search the "rx and tx" functions mentioned above-that is where I am looking, and how will I test this, means by writing on the device file and then immediately receiving the same.
I also have a sample patch, but not sure, whether it will work.
Any help would be appreciated...
Abhijit
`## -2112,6 +2116,7 ## static int serial8250_startup(struct uart_port *port)
if (is_real_interrupt(up->port.irq))
up->port.mctrl |= TIOCM_OUT2;
+ up->port.mctrl |= TIOCM_LOOP;
serial8250_set_mctrl(&up->port, up->port.mctrl);
/* Serial over Lan (SoL) hack:
This will set UART to work in internal loop-back mode.`
Related
This is driving me nuts for a couple of days now, so maybe you guys can give me some insights into what is going wrong.
I'm trying to read some data from an EEPROM (24LC16B) with an STM32(F0), but it just doesn't let me. I've tried an Arduino, which worked and does still work, so I do know that the wiring is correct.
This is my function to read the EEPROM data. (It is cut down to the very basis, just for testing): (Pastebin of my I2C_setup function)
uint16_t readEEPROMData(uint16_t deviceAddress, int memAddress){
// Wait while I2C peripheral is not ready
I2C_WaitForFlag(I2C_ISR_BUSY);
// Start I2C write transfer for 2 bytes, do not end transfer (SoftEnd_Mode)
I2C_TransferHandling(I2C1, 0xA2, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
I2C_WaitForFlag(I2C_ISR_TXIS);
// For testing purpose, be sure to generate a stop command...
I2C_TransferHandling(I2C1, 0xA2, 0, I2C_AutoEnd_Mode, I2C_Generate_Stop);
return I2C_COMM_STATUS;
}
Here's an pastebin of the Arduino library I used.
I've used a logic analyzer to see how the communication is going, and now I really don't understand it. Here's a printscreen of the working Arduino version:
And here's a printscreen of the STM32 communication:
Logic analyzer exports (viewable with Saleae Logic)
As you can see, I'm using the same address (although I had to use 0xA2 with the STM32), and there are no weird things happening, besides the NACK. So what could possible be wrong?
Confirm if all bus timing requirement are satisfied.
Confirm if their is adequate delay after every write cycle (5 mS)
Confirm is bus capacitance falls under permissible limit of I2C (400 pF - Theoretically).
Confirm if the correct VCC is supplied
As mentioned by you are interfacing EEPROM with MCU using cable you need to conform on capacitance.
You can use an oscilloscope to check if their are any distortion in waveform. You can use a LCR meter to check the capacitance.
Try reducing bus speed 25kHz to 50 kHz and check waveform.
Try increasing the strength of pull resister.
The problem with the wrong VCC capacity (4.2v instead of 5v for example) is, that the timing can be different to. (not fully verified, but it fixed the problem)
I'm trying to do something really simple and I'm having a bit of trouble getting it to work. I'm working with the MPL3115A2 Altitude/Pressure Sensor and a pic32 uC32 board, and I'm trying to communicate between the two using I2C. (uC32 board is similar enough to arduino that it's practically the same in terms of coding).
I'm using the wire library and I'm simply trying to read register 0x0C from the MPL3115A2, which should give me the device ID.
Here's a code snippet (the define is at the top of the code and the rest is in the main loop):
#define barAddress 0x60
Wire.beginTransmission(barAddress);
Wire.send(0x0C);
Wire.endTransmission();
Wire.requestFrom(barAddress, 1);
uint8_t a = Wire.receive();
Serial.println(a, HEX);
So I start the transmission with address 0x60 (From the datasheet: The standard 7-bit I2C slave address is 0x60 or 1100000. 8-bit read is 0xC1, 8-bit write is 0xC0.). Then I send 0x0C because that's the register I want to access. I then end transmission, and request 1 byte from address 0x60, receive that bit into a 8-bit variable, then print it.
The problem I run into is that when I print it, I just get 0. I don't get the device ID, just 0. No matter what register I try to read, I get 0.
I've been banging my head against a wall for the past few days trying to get this to work. I've attached something I've captured with a logic analyzer, as well as a list of registers from the datasheet of the MPL3115A2 that I've been trying to access.
Using a logic analyzer I can see the clock and data lines. The clock seems normal and the data line gives me the following:
START
Write['192'] + ACK
'12' + ACK
STOP
START
Read['193'] + ACK
'0' + NAK
STOP
This all seems correct to me (192 and 193 come from 8-bit write and read being 0xC0 and 0xC1), except for the '0'. I should be getting the device ID, not 0.
Thanks for any help with this!
You should look at Freescale's app note AN4481, which is referred to by the datasheet. Page 5 shows the single-byte read operation which is what you are doing, except that the register address write must not be followed by a STOP but instead uses a REPEATED-START.
I'm not familiar with the Wire library but it look like all you need to do is remove the Wire.endTransmission(); between the send and requestFrom.
Hopefully, this will solve your problem.
I am doing a class project involving an Arduino Uno and a Picaxe 14m2.
I am in the middle of attempting to code a program for the Arduino Uno that will allow me to send and output value to the input on the Picaxe.
So in layman's, this is what I wish to achieve:
I want the Arduino to check a sensor, and if the sensor returns a specific value. (- I know this part, but not the next.) I then want the Arduino to send a value (HIGH, or 1 .. something like that) as an output to one of the Picaxe input pins. I then need the Picaxe to notice a value has been sent, and then do something else.
Any help would be appreciated.
Thanks.
If you are looking for that, you may want to specify what kind of PICAXE you have.
Since there is a difference in the types of these chips.
After that you may wanna look over the datasheet of the PICAXE so that you can find the instructions set and the type of program memory you have, "EEPROM....".
After that:
List your Is/Os, inputs and outputs.
Set your source code editor.
Write the source code and burn it to the PICAXE program
memory.(C, Assembly...)
Write your Arduino code, setting the Is/Os and telling the
Arduino how to deal with the signals in and out.(C language)
Make a circuit diagram for the hardware you are going to connect
between both chips.
Don't forget to see the loading effects on both the Arduino and
the PICAXE, because you don't want to burn your project hardware
after all.
Test your project and note that you will have to troubleshoot
both software and hardware whenever a problem occurs.
I suggest that you use the Oscilloscope to test the signals going in or coming out of both circuits + the sensor's signal.
For any extra thing you need the PICAXE to do, use If statements, because they are not so technical to implement and they are easy to write and troubleshoot.
For your scheme, you are actually making the Arduino give instructions to the PICAXE through a variable signal coming from a sensor.
^send me feedback and I will help more.
You will probably want to look into using UART (aka Serial) or i2c communication.
Serial communication should work with any PICAXE and Arduino, While i2c Will only work if you are using the X2 Series PICAXE Chips. i2c's main advantage is when using multiple slave devices (plus the master device, i.e. more than just 2 devices total) in which you can use the same two wires for up to around 128 devices. Serial (UART) communication is simpler, and only needs one wire (plus a common ground) to send data one way, it is what i'll show for the rest of this answer
Here is the manual entry for serial input for the PICAXE, and Here's the entry for serial output from the Arduino. The code you will need given your question will be something like the following:
For the arduino:
void setup(){
Serial.begin(9600);
}
void loop(){
if (conditionMet){ //whatever the condition is in your code
int bytesSent = Serial.write(“HIGH”); //send the string “HIGH"
}
}
and for the PICAXE:
main:
serin 6, T9600, ("HIGH") 'uses qualifier to look for exact message "HIGH"
'do whatever when criteria met
goto main
I'm new to microcontroller programming and I have interfaced my microcontroller board to another device that provides a status based on the command send to it but, this status is provided on the same I/O pin that is used to provide data. So basically, I have an 8-bit data line that is used as an output from the microcontroller, but for certain commands I get a status back on one of the data lines if I choose to read it. So I would be required to change the direction of this one line to read the status thus converting this line as an ouput to an input and then back to an output. Is this acceptable programming or will this changing of the I/O pin this frequently cause instability?
Thanks.
There should not be any problem with changing the direction of the I/O line to read the status returned by the peripheral provided that you change the state of the line to an input before the peripheral starts to drive the line and then do not try to drive the line as an output until the peripheral stops driving it. What you must try to avoid is contention between the two driver devices, i.e. having the two ends being driven to opposite states by the processor and peripheral. This would result in, at best a large spike in the power consumption or worse blown pin driver circuitry in the processor, peripheral or both.
You do not say what the processor or peripheral are so I cannot tell whether there are any control bits in the interface that enable the remote device to output the status so that you can know whether the peripheral is driving the line at any time.
I've done this on digital I/O pins without any problems but I'm very far from an expert on this. It probably depends entirely on which microcontroller you are using though.
Yes, it's perfectly fine to change I/O direction on microcontroller repeatedly.
That's the standard method of communicating over open-collector buses such as I2C and the iButton. (see PICList: busses for links to assembly-language code examples).
transmit 0 bit: set output LATx bit to 0, and then set TRISx bit to OUTPUT.
transmit 1 bit: keep output LATx bit at 0, and set TRIS bit to INPUT (let external resistor pull-up line to high)
listen for response from peripheral: keep output LATx bit at 0, and set TRIS bit to INPUT. Let external resistor pull-up line to high when peripheral is transmitting a 1, or let the peripheral pull the line low when peripheral is transmitting a 0. Read the bit from the PORTx pin.
If both ends of the bus correctly follow this protocol (in particular, if neither end actively drives the line to high), then you never have to worry about contention or current spikes.
It`s important to remember that any IO switching in high speed generates EMI.
Depending of switching frequency, board layout and devices sensibilities, this EMI can affect performance and reliability of your application.
If you are having problems in your application use an oscilloscope to check for irradiated EMI in your board lanes.
We've got a system running XP embedded, with COM2 being a hardware RS485 port.
In my code, I'm setting up the DCB with RTS_CONTROL_TOGGLE. I'd assume that would do what it says... turn off RTS in kernel mode once the write empty interrupt happens. That should be virtually instant.
Instead, We see on a scope that the PC is driving the bus anywhere from 1-8 milliseconds longer than the end of the message. The device that we're talking to is responding in about 1-5 milliseconds. So... communications corruptions galore. No, there's no way to change the target's response time.
We've now hooked up to the RS232 port and connected the scope to the TX and RTS lines, and we're seeing the same thing. The RTS line stays high 1-8 milliseconds after the message is sent.
We've also tried turning off the FIFO, or setting the FIFO depths to 1, with no effect.
Any ideas? I'm about to try manually controlling the RTS line from user mode with REALTIME priority during the "SendFile, clear RTS" cycle. I don't have many hopes that this will work either. This should not be done in user mode.
RTS_CONTROL_TOGGLE does not work (has a variable 1-15 millisecond delay before turning it off after transmit) on our embedded XP platform. It's possible I could get that down if I altered the time quantum to 1 ms using timeBeginPeriod(1), etc, but I doubt it would be reliable or enough to matter. (The device responds # 1 millisecond sometimes)
The final solution is really ugly but it works on this hardware. I would not use it on anything where the hardware is not fixed in stone.
Basically:
1) set the FIFOs on the serial port's device manager page to off or 1 character deep
2) send your message + 2 extra bytes using this code:
int WriteFile485(HANDLE hPort, void* pvBuffer, DWORD iLength, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped)
{
int iOldClass = GetPriorityClass(GetCurrentProcess());
int iOldPriority = GetThreadPriority(GetCurrentThread());
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
EscapeCommFunction(hPort, SETRTS);
BOOL bRet = WriteFile(hPort, pvBuffer, iLength, pdwWritten, lpOverlapped);
EscapeCommFunction(hPort, CLRRTS);
SetPriorityClass(GetCurrentProcess(), iOldClass);
SetThreadPriority(GetCurrentThread(), iOldPriority);
return bRet;
}
The WriteFile() returns when the last byte or two have been written to the serial port. They have NOT gone out the port yet, thus the need to send 2 extra bytes. One or both of them will get trashed when you do CLRRTS.
Like I said... it's ugly.
Any ideas?
You may find that there's source code for the serial port driver in the DDK, which would let you see how that option is supposed to be implemented: i.e. whether it's at interrupt-level, at DPC-level, or worse.
Other possibilities include rewriting the driver; using a 3rd-party RS485 driver if you can find one; or using 3rd-party RS485 hardware with its own driver (e.g. at least in the past 3rd parties used to make "intelligent serial port boards" with 32 ports, deep buffers, and its own microprocessor; I expect that RS485 is a problem that's been solved by someone).
8 milliseconds does seem like a disappointingly long time; I know that XP isn't a RTOS but I'd expect it to (usually) do better than that. Another thing to look at is whether there are other high-priority threads running which may be interfering. If you've been boosting the priorities of some threads in your own application, perhaps instead you should be reducing the priorities of other threads.
I'm about to try manually controlling the RTS line from user mode with REALTIME priority during the "SendFile, clear RTS" cycle.
Don't let that thread spin out of control: IME a thread like that can if it's buggy preempt every other user-mode thread forever.