Interfacing a slow device to a MCF5270 Microcontroller - c

I'm looking for ways to interface a slow device (an ADC - ~1.2MHz) to my mcf5270 microcontroller, which is a rather fast device (~150MHz). I am using ADC0817, and have tried the following: GPIO read off the data lines, memory mapped access (since the adc is uP compatible).
When mapped as a location in memory, I am using the maximum wait states (15ws, which is about 107ns). The mcf5270 does not support any further waiting without using their bus model (which the ADCs do not support).
Using GPIO, only junk values are read.
Note: The ADC is actually working, and other than reading data the interface to it is functional. I am using C/C++ and assembly.
In short, I am looking for suggestions for ways in which to try to read the data off the ADC0817.
Comments and responses are greatly appreciated.

You could trigger the ADC through some GPIO, do an appropriate number of NOPs and then read the value. Also, you'd need to disable interrupts while doing this.

I think memory mapped should work - normally I would wait for the interrupt from the ADC, then read the byte at the specified address. Since you get an interrupt, there is no wait state needed. Am I missing something? GPIO should also work. How do you know the ADC is working? Can you put a logic analyzer on the data & interrupt to prove the ADC is producing the correct output?

I think from what he's saying MMIO wont' work because he would need more than the maximum number of wait states on the bus to get the glue logic to respond - ie, the A/D won't set its bus pins soon enough for the uC to be happy. That's a problem sometimes.
But the GPIO approach should work. If junk values are being read I assume that you aren't following the timing diagram provided. You'll have to be able to wait certain amounts of time after you signal a read before the data is valid. Check out the datasheet for specifics.

Related

When is a Cortex write to a device realised

When writing to device registers on a Cortex M0 (in my case, on an STM32L073), a question arises as to how careful one should be in a) ordering accesses to device memory and b) deciding that a change to a peripheral configuration has actually completed to the point that any dependencies become valid.
Taking a specific example to change the internal voltage regulator to a different voltage. You write the change to PWR->CR and read the status from PWR->CSR. I see code that does something like this:
Write to PWR->CR to set the voltage range
Spin until (PWR->CSR & voltage flag) becomes zero
In my mind there are three issues here:
Access ordering. This is Device Memory so transaction order is preserved relative to other Device access transactions. I would assume this means a DSB is not required between the write to CR and the read from CSR. A linked question and the answer to this is: [ARM CortexA]Difference between Strongly-ordered and Device Memory Type
Device memory can be buffered. Is there a possibility that a write to CR could still be in process when the read from CSR occurs. This would mean that the voltage flag would be clear and the code would proceed. In actual fact the flag hasn't gone high yet!
Hardware response time. Is there a latency between the write and the effects becoming final? In actuality this should always be documented - for the STM32 the docs definitively say that the flag is set when the CR register changes.
Are there any race condition possibilities here? It's really the buffering that worries me - that a peripheral write is still in progress when a peripheral read takes place.
Access ordering.
Accesses are strongly ordered and you do not need barrier instructions to read back the same register.
Device memory can be buffered. Is there a possibility that a write to CR
Yes, it is possible. But it is not because of buffering but because of the bus propagation time. It may take several clocks before a particular operation will go through all bridges.
Hardware response time. Is there a latency between the write and the
effects becoming final
Even if there is a latency it is not important from your point of view. If you set bit in the CR register and wait for the result in the status register. Simply wait for the status bit to have the expected value.

How to exploit interrupts for data transfer over SPI peripheral

I have been implementing device driver for the SPI peripheral of the MCU in C language.
I would like to exploit interrupt mechanism for reception and also for transmission.
As far as the reception part I think that I can implement this via exposing
the function SpiRegisterCallback into the SPI driver interface. This function
enables the client register its function which will be invoked as soon as
data byte is received (reception buffer full interrupt is invoked).
As far as the transmission part I would like to use some SpiTransmit function
which will receive pointer to the data bytes to be transmitted and number of bytes
to be transmitted. As far as implementation I am going to define some internal
callback function of the SPI driver. This internal callback will be registered
for transmission buffer empty interrupt. In this callback function the passed data bytes will be gradually placed into the transmission buffer. I am not sure whether this approach
is appropriate. Can anybody give me an advice how to implement SPI peripheral
driver which exploits interrupts for data transmission? Thanks in advance for any
suggestions.
SPI is often very real-time critical, introducing a callback with function pointers means needless overhead code. The actual copying of data from SPI to RAM must be done internally by your driver. That's all the ISR should be doing. Some general guidance can be found here.
So your ISR should be filling up a buffer, then swap pointers to buffers (no slow memcpy!) in a protected way, so that the caller always has one buffer with valid data, and the ISR always has one working buffer to fill up. Let the caller poll a flag rather than to invoke a callback from inside an ISR. I like to use tripple buffering if I can spare the RAM. That is: one buffer for the ISR, one buffer for the caller and one spare that the ISR can swap with without disrupting the caller.
This is all rather intricate to code and most programmers get it wrong. DMA is superior to interrupts here, so you should really be considering DMA instead. This is something you should be considering when picking MCU.
A request for "any suggestions" does not really make this a great question because multiple answers may be acceptable, and few will be comprehensive. It invites comments rather then answers. However I will indulge:
First, this is not by any definition an exploit. To "exploit" implies making use of something for a purpose it was not intended - that is not the correct term in this case, you are not "exploiting" the interrupt mechanism, you are simply using it.
At high clock rates, in some cases the interrupt latency and context switch time involved in processing the interrupts may be less efficient than a simple busy-wait. If the transfers are more than two or three bytes at a time, you should in any case consider using DMA if available - so the interrupt will be the DMA interrupt for a complete transfer rather then a single character. For applications such as SD card interfacing or EEPROM, DMA will have a significant performance impact and free up the CPU to do other useful work concurrently. A driver that uses a busy-wait for single byte/word transfers and DMA for block transfers may be optimal. This is particularly true perhaps if you are using an RTOS and the ISR triggers a task context to process the data - the context switch overhead may be nearly as much or more than a busy-wait for a single byte. If your SPI clock is > 1MHz for example, you will wait 8us for a byte transfer, your ISR and call backs could easily be greater then that, in which case it is not worthwhile.
So my advice here is to only consider interrupts for SPI if you are using a slow clock and can get other useful work done whilst waiting for the interrupt.
A problem with allowing call-backs in interrupts is it allows the callback provider to do things ill-advised or illegal in an interrupt context, and you loose the ability to control the processing time of the interrupt. It is fine perhaps if the callback is intended for use by someone writing a device driver - they should be aware of what they are doing, but this is the device driver.

Relaying UART1 with UART2 within an ISR() (PIC24H)

I am programming a microcontroller of the PIC24H family and using xc16 compiler.
I am relaying U1RX-data to U2TX within main(), but when I try that in an ISR it does not work.
I am sending commands to the U1RX and the ISR() is down below. At U2RX, there are databytes coming in constantly and I want to relay 500 of them with the U1TX. The results of this is that U1TX is relaying the first 4 databytes from U2RX but then re-sending the 4th byte over and over again.
When I copy the for loop below into my main() it all works properly. In the ISR(), its like that U2RX's corresponding FIFObuffer is not clearing when read so the buffer overflows and stops reading further incoming data to U2RX. I would really appreciate if someone could show me how to approach the problem here. The variables tmp and command are globally declared.
void __attribute__((__interrupt__, auto_psv, shadow)) _U1RXInterrupt(void)
{
command = U1RXREG;
if(command=='d'){
for(i=0;i<500;i++){
while(U2STAbits.URXDA==0);
tmp=U2RXREG;
while(U1STAbits.UTXBF==1); //
U1TXREG=tmp;
}
}
}
Edit: I added the first line in the ISR().
Trying to draw an answer from the various comments.
If the main() has nothing else to do, and there are no other interrupts, you might be able to "get away with" patching all 500 chars from one UART to another under interrupt, once the first interrupt has ocurred, and perhaps it would be a useful exercise to get that working.
But that's not how you should use an interrupt. If you have other tasks in main(), and equal or lower priority interrupts, the relatively huge time that this interrupt will take (500 chars at 9600 baud = half a second) will make the processor what is known as "interrupt-bound", that is, the other processes are frozen out.
As your project gains complexity, you won't want to restrict main() to this task, and there is no need to for it be involved at all, after setting up the UARTs and IRQs. After that it can calculate π ad infinitum if you want.
I am a bit perplexed as to your sequence of operations. A command 'd' is received from U1 which tells you to patch 500 chars from U2 to U1.
I suggest one way to tackle this (and there are many) seeing as you really want to use interrupts, is to wait until the command is received from U1 - in main(). You then configure, and enable, interrupts for RXD on U2.
Then the job of the ISR will be to receive data from U2 and transmit it thru U1. If both UARTS have the same clock and the same baud rate, there should not be a synchronisation problem, since a UART is typically buffered internally: once it begins to transmit, the TXD register is available to hold another character, so any stagnation in the ISR should be minimal.
I can't write the actual code for you, since it would be supposed to work, but here is some very pseudo code, and I don't have a PIC handy (or wish to research its operational details).
ISR
has been invoked because U2 has a char RXD
you *might* need to check RXD status as a required sequence to clear the interrupt
read the RXD register, which also might clear the interrupt status
if not, specifically clear the interrupt status
while (U1 TXD busy);
write char to U1
if (chars received == 500)
disable U2 RXD interrupt
return from interrupt
ISR's must be kept lean and mean and the code made hyper-efficient if there is any hope of keeping up with the buffer on a UART. Experiment with the BAUD rate just to find the point at which your code can keep up, to help discover the right heuristic and see how far away you are from achieving your goal.
Success could depend on how fast your micro controller is, as well, and how many tasks it is running. If the microcontroller has a built in UART theoretically you should be able to manage keeping the FIFO from overflowing. On the other hand, if you paired up a UART with an insufficiently-powered micro controller, you might not be able to optimize your way out of the problem.
Besides the suggestion to offload the lower-priority work to the main thread and keep the ISR fast (that someone made in the comments), you will want to carefully look at the timing of all of the lines of code and try every trick in the book to get them to run faster. One expensive instruction can ruin your whole day, so get real creative in finding ways to save time.
EDIT: Another thing to consider - look at the assembly language your C compiler creates. A good compiler should let you inline assembly language instructions to allow you to hyper-optimize for your particular case. Generally in an ISR it would just be a small number of instructions that you have to find and implement.
EDIT 2: A PIC 24 series should be fast enough if you code it right and select a fast oscillator or crystal and run the chip at a good clock rate. Also consider the divisor the UART might be using to achieve its rate vs. the PIC clock rate. It is conceivable (to me) that an even division that could be accomplished internally via shifting would be better than one where math was required.

Write value to parallel port register

I'm trying to write to my lpt register with the function outb(0x378,val);
well.. I tried to debug with the call int ret=inb(0x378); I always get the ret=255 no matter what value I insert with outb before.
*I'm writing on the kernel mode since my program is a driver, therefore I didn't use ioperm() etc.
thank you in advance.
You have the parameters of outb function wrong, correct order is :
outb(value, port)
so you have to change your code to do:
outb(val, 0x378)
For more details please read Linux I/O Programming Howto .
Do you know for a fact that you have a parallel port installed at that address?
Get yourself a small low-current LED. Stick the long end in one of pin 2 (LSB) to pin 9 (MSB) and the short end in pin 25 (ground).
Try writing various values and see if you can get the LED to change by the bit value of what you write.
This should work (unless as previously mentioned you've gotten it programmed in an input mode) Being able to read back the port value is less certain, depending on the type of parallel port and implementation details (for example, you probably couldn't with the buffer chip that implemented it in the original PC)
Also note that most USB "printer" adapters don't give you bitwise register access. Something hanging off of the PCI or PCMCIA, etc may also have problems with direct register access at the legacy port address. There are nice USB parallel interface chips such as the FT245 and successors which you can use if you don't have a "true" parallel port hanging off the chipset available.
Have you set the direction register? If it is set as input then you will read what is on the port.
inb(0x378) is not required to return what was written; at least I've seen chips to behave so. Well, since you, at some point, have called outb, you know what's on anyway.

RS232 Communication - Can I use it to create a steady state signal?

In all honesty, I think the answer is "no;" however, I want to get a second opinion. Basically, I need one micro-controller device to send a steady signal to another one, but the communicate between them is using RS232. So I think that I have to create/update the communication messages to get it to do what I want.
What do you think?
You should be able to set something like DTR (Data Terminal Ready), pin 20, or DSR (Data Set Ready), pin 6, high and keep it there as your steady-state signal. This is how modems/terminals detect that there is a device on the other end that is ready to communicate. It all depends on what level of access you have to the hardware through your driver.
[EDIT] This doesn't involve sending data, although you could still do that using TX/RX, pins 2 & 3.
RS-232 Reference on wikipedia
You mean a fixed voltage? Not a square wave? (the letter U) What about a break command (if you want to call it a command)?
Certainly you can use one of the control lines if that helps...Or are you specifically looking for something out of the TX?
If the question is "can I alter the DC state of the Tx line", then the answer is that many uarts (including the ones in PCs) can be asked to create a 'break' condition, which is the opposite to the normal idle condition of the line.
So you can turn 'break' on and off and toggle the line like that.
It might be possible to do something like that, provided you don't mind a burst-like interface. One micro could transmit a byte and the other could do something to that byte and send it back as a response.
If you can control both ends of the line, you may be able to turn the rs-232 tx and rx lines into regular logic lines to give that information.
In most situations, however, each end periodically sends a byte of status information that contains 8 possible digital values - gives much more status information.
A timer on the receiving end is reset everytime a message is received, and if the timer times out then the message has taken too long and yo can act on missing status message.
As others have pointed out, if you're using hardware flow control you have some status lines available as well, though in many cases those lines aren't implemented so that may not be an option.
-Adam
Steady signal could mean:
steady burst of charaters: keep the send buffer full
line held high or low : send nothing or send continual breaks
I think it depends to a large extent on the UART that you are using, e.g. link text, and the level of access you have to it under software. If you check the data sheet there are often ways of controlling most of the pins directly for testing purposes, but you will need to go at it from a pretty low level.
At a higher level, tvanfosson's answer is pretty much the way i'd do it.
While the first answer is correct it may not be possible to use this technique (using DTR or DSR) on many micro controllers as they may not have those signals (many micro controllers may just have the basic RX/TX lines and you would often have to use other i/o ports if you wanted extra control/status lines. However, all is not lost, many RS232 controllers allow you to set the TX line to 'mark' or 'space' (i.e set the TX line to logic high or low). This would allow you to get your steady state signal. The RX line on the receiver can be checked to see if its at mark or space level.

Resources