8051 external ram(62256) and also using address & data lines as GPIO - c++

My application requires 8051 with external RAM 32K(62256) I plan to use one chip(62256) to address 32k, and I want to use the other 32K to access GPIO like higher 32k goes to RAM & lower 32k to keypad and other GPIO peripherals is this possible to do so?

Yes, it's possible. In this particular case, it's even pretty simple/easy.
You're splitting the address space in half. When you address the lower half of the address space, A15 will be low. When you address the upper half, A15 will be high.
The 62256 has an active low chip-enable pin (CE#), meaning the chip is enabled only when CE# is low. You want to enable the 62256 only when A15 is high, so you'll connect A15 on the 8051 to an inverter, and from there to CE# on the 62256.
Although you haven't described the other chips in any real detail, the same basic idea applies with them--you wire up logic that enables each chip if and only if the address is in the correct range. For example, let's say you have some peripheral that looks to the processor like 256 bytes of memory. To keep things really simple, let's assume this peripheral has an AD0 through AD7 that it uses for addresses and data, and uses the same bus cycles as an 8051.
Since you want the CPU to see that chip in the first 256 bytes of the address space, that means it should be active only when all the higher address lines (A8 through A15) are low. So, we feed them into an 8-input OR gate, so its output is high if any of its inputs are high.
So, as a starting point, your decoding circuitry would look vaguely like this:
This is just a sketch though. Just for example, you'll also need circuitry for the OE# pin on the 62256, which will be activated by the WR# pin on the 8051, and unless the bus cycles for the other chips happen to match perfectly with those for the 8051, you'll end up with (for example) some buffers to hold data coming from one until it's time to send it to the other.

Related

Sandy Bridge QPI bandwidth perf event

I'm trying to find the proper raw perf event descriptor to monitor QPI traffic (bandwidth) on Intel Xeon E5-2600 (Sandy Bridge).
I've found an event that seems relative here (qpi_data_bandwidth_tx: Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data. Unit: uncore_qpi) but I can't use it in my system. So probably these events refer to a different micro-architecture.
Moreover, I've looked into the "Intel ® Xeon ® Processor E5-2600 Product Family Uncore Performance Monitoring Guide" and the most relative reference I found is the following:
To calculate "data" bandwidth, one should therefore do:
data flits * 8B / time (for L0)
or 4B instead of 8B for L0p
The events that monitor the data flits are:
RxL_FLITS_G0.DATA
RxL_FLITS_G1.DRS_DATA
RxL_FLITS_G2.NCB_DATA
Q1: Are those the correct events?
Q2: If yes, should I monitor all these events and add them in order to get the total data flits or just the first?
Q3: I don't quite understand in what the 8B and time refer to.
Q4: Is there any way to validate?
Also, please feel free to suggest alternatives in monitoring QPI traffic bandwidth in case there are any.
Thank you!
A Xeon E5-2600 processor has two QPI ports, each port can send up to one flit and receive up to one flit per QPI domain clock cycle. Not all flits carry data, but all non-idle flits consume bandwidth. It seems to me that you're interested in counting only data flits, which is useful for detecting remote access bandwdith bottlenecks at the socket level (instead of a particular agent within a socket).
The event RxL_FLITS_G0.DATA can be used to count the number of data flits received. This is equal to the sum of RxL_FLITS_G1.DRS_DATA and RxL_FLITS_G2.NCB_DATA. You only need to measure the latter two events if you care about the break down. Note that there are only 4 event counter per QPI port. The event TxL_FLITS_G0.DATA can be used to count the number of data flits transmitted to other sockets.
The events RxL_FLITS_G0.DATA and TxL_FLITS_G0.DATA can be used to measure the total number of flits transferred through the specified port. So it takes two out of the four counts available in each port to count total data flits.
There is no accurate way to convert data flits to bytes. A flit may contain up to 8 valid bytes. This depends on the type of transaction and power state of the link direction (power states are per link per direction). A good estimate can be obtained by reasonably assuming that most data flits are part of full cache line packets and are being transmitted in the L0 power state, so each flit does contains exactly 8 valid bytes. Alternatively, you can just measure port utilization in terms of data flits rather than bytes.
The unit of time is up to you. Ultimately, if you want to determine whether QPI bandwdith is a bottleneck, the bandwdith has to be measured periodically and compared against the theoretical maximum bandwidth. You can, for example, use total QPI clock cycles, which can be counted on one of the free QPI port PMU counters. The QPI frequency is fixed on JKT.
For validation, you can write a simple program that allocates a large buffer in remote memory and reads it. The measured number of bytes should be about the same as the size of the buffer in bytes.

how to offload precise ADC oversampling with RISC-V GD32VF103CBT6 Development Board

I'm hoping to work up a very basic audio effects device using a RISC-V GD32VF103CBT6 Development Board. I have managed to do some hardware-interrupt-based sampling with another MCU, but I'm a bit confused by the documentation for the RISC-V board. Chapter 11 in the user manual. I haven't the slightest idea how to turn the instructions there into actual C/C++ code. Sadly, their github repo has almost no examples at all, and none appear to deal with high speed sampling. There's also a datasheet in this github repo but I haven't been able to find any specific code examples or revealing instruction in there, either.
What I want to do is:
Perform the calibration described in the user manual, which must precede sampling operations.
collect 12-bit audio samples of audio signal voltage off an external pin using its oversampling capability to sum numerous 12-bit samples into a single 16-bit sample at a high sampling rate. Ultimately I want audio sampled with 16-bits at 48khz-96khz.
I need help instructing the MCU to collect these samples using its built-in hardware features.
I want to continuously sample, offloading as much as possible to built-in hardware functions so I can leave enough processing overhead left to do a bit of signal processing for simple effects.
Section 11.4.1 clearly says
Calibration should be performed before starting A/D conversion.
The calibration is initiated by software by setting bit CLB=1. CLB bit stays at 1 during all the calibration sequence. It is then cleared by hardware as soon as the calibration is completed.
The internal analog calibration can be reset by setting the RSTCLB bit in ADC_CTL1 register.
Calibration software procedure:
1) Ensure that ADCON=1.
2) Delay 14 ADCCLK to wait for ADC stability
3) Set RSTCLB (optional)
4) Set CLB=1.5.Wait until CLB=0.
Question 1: How do I set these memory registers as these instructions indicate. I need a code example, and the manufacturer provides none.
Question 2: How do I delay 14 ADDCCLK in C/C++. Seems like a loop would be enormously inefficient. Should I call sleep()? Any explanation of ADDCCLK also helpful.
This also seems important, but I have no idea what it portends:
The ADCCLK clock provided by the clock controller is synchronous APB2 clock. The RCU controller has a dedicated programmable prescaler for the ADC clock.
I am not at all certain but I think this is the conversion mode I want:
Continuous conversion mode
This mode can be run on the regular channel group. The continuous conversion mode will be enabled when CTN bit in the ADC_CTL1 register is set. In this mode, the ADC performs conversion on the channel specified in the RSQ0[4:0]. When the ADCON has been set high, the ADC samples and converts specified channel, once the corresponding software trigger or external trigger is active. The conversion data will be stored in the ADC_RDATA register.
Software procedure for continuous conversion on a regular channel. To get rid of checking, DMA can be used to transfer the converted data:
1.Set the CTN and DMA bit in the ADC_CTL1 register
2.Configure RSQ0 with the analog channel number
3.Configure ADC_SAMPTx register
4.Configure ETERC and ETSRC bits in the ADC_CTL1 register if in need
5.Prepare the DMA module to transfer data from the ADC_RDATA.
6.Set the SWRCST bit, or generate an external trigger for the regular group
ADCCLK refers the input clock of the ADC. May be take a look at your datasheet. The most µC have a block diagram of the clock architecture of the µC usually there is a main system clock and then the different peripherals have a prescaler that you can program and which divide the system clock by some power of 2.
so 14 ADCCLK cycles mean that its not 14 CPU cycles but 14 ADC-Input-Clock edges.
For example if the ADC prescaler is set to 64 then you have to wait 64*14 CPU clock cycles.
How to wait at all:
Mostly (I do not know if such a thing is present on your device) peripherals have a busy flag that is set as long the current operation is ongoing. So may be you can poll this flag (e.g. like while (ADC0_FLAGS & ADC_ISBUSY); ).
Another option may be checking if there is an interrupt that signals the completion of your operation. But at least for the calibration the simplest thing would be to start the calibration and just use a wait or delay function that just wastes a bit of time.
I personally would start the calibration on system start up and then doing other initialization stuff. May be delay at end of setup a few milliseconds to make sure all components on the board are powerd up correctly. After that the ADC should be already finished a long time.

Data sheet for chip does not state how to communicate with it

So to start off I am definitely not a Computer Engineer, but I am trying to learn. I found a couple of (93C46CB3) chips along with some other insignifcant chips in a bag, thanks Dad! I studied the data sheet and I figured out which pins do what on the chip, but I have yet to figure out how to read and write to it. It says it's serial but it does not say what baud rate it is. Also, it does not say how fast I should be turning on and off the pins. Does it use PWM? If so, how fast? The data sheet is here
http://www.datasheetspdf.com/datasheet/93C46CB3.html
PG. 7 is where the chart is for reading and writing but it does not say how long those intervals are. "S" "D" and "Q" are all pins btw.
I am trying to read and write its content using an Arduino, and or a Raspberry Pi, whichever works I just need it to work. Thanks in advance!
tldr; How fast do I turn my pins on and off for this chip, and what is the baud rate on this if it has serial communication?
The manufacturer has application notes on the wiring and protocol for their 93 Series Microwire devices
http://ww1.microchip.com/downloads/en/AppNotes/01004a.pdf
http://ww1.microchip.com/downloads/en/AppNotes/01020B.pdf
http://ww1.microchip.com/downloads/en/AppNotes/01029A.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00993a.pdf
and the source in C for PIC microcontrollers is in:
http://ww1.microchip.com/downloads/en/AppNotes/AN1004.zip
TLDR:
Supports SPI or Microwire protocols
The speed for your chip is stated in the datasheet to have a clock frequency of 3MHz but I would recommend 2MHz as that covers all chips in this series.
The most significant bit is sent first
Clock polarity is type 0 (positive)
Clock phase is type 0 (rising edge)
Arduino init example:
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
This will work with pin 2 connected to SCK, pin 3 connected to MOSI, and pin 4 connected to MISO.
Seems like your chip is actually a 93C46, the CB probably stands for some chip options.
datasheet 93C46 Microchip
This chip is manufactured by many manufacturer, so you may try to find out which manufacturer to get the particular manufacturer datasheet to be sure there is no differences, even there should not be.
If this is true, it's a serial EEPROM which is basically a non-volatile memory. This chip is just a simple memory you can write and read to, but does not contain anything else so you cannot "program" it.
This chip communicate using a SPI bus (Serial peripheral bus) which has one clock line, and two data lines. The chip is a slave, passive component and you need a microcontroller to communicate with it.
I suggest you do further reading on the SPI bus and then on microcontrollers, then you'll be able to write and read its memory.
Serial Peripheral Bus

What is wrong with com port comminucation if I get CE_FRAME errors?

I am trying to understand why I get CE_FRAME error in a serial communication. The documentation reads:
The hardware detected a framing error. Returned when the SERIAL_LSR_FE bit is detected in the LSR hardware register.
This is the framing error indicator. It is set whenever the hardware detects that the incoming serial data unit does not have a valid stop bit. This bit is cleared by reading this register:
define SERIAL_LSR_FE 0x08
But I don't really know what shall I do with this valid stop bit. Can I just ignore this?
I have no other issues with the communication. Every packet of data (send by the device) is being captured on the PC. On the PC I am using ClearCommError() to detect statistics of the channel, and from time to time I got this CE_FRAME flag on.
I am not sure if I have to provide details about the CreateFile() and SetCommState() function calls in my code, as there are nothing 'special' about them. But if needed, I can.
If you are programming on Windows then the application programmer does not set start and stop bits, the 'system' takes care of applying the start/stop bits as well as possible parity bits, baud rate and even some other settings. The critical ones are baud rate, start and stop bits and parity bits.
The system being the hardware or operating system. I think it is the UART chip which adds the start and stop bits. But you need to set the actual configuration to use in software.
What you do have to do is set the start and stop bits the same on both ends. So if you are communicating with a device which uses 1 start bit and 2 stop bits, then you have to set this same setting for your communication end.
You are likely to get framing errors if these settings are NOT set the same on both ends of the communication. I have seen framing errors where for example I set the baud rate 1200 one end but 9600 the other end. Actually my start and stop bits were correctly set both ends. So it may well be something simple like that.

Low latency serial communication on Linux

I'm implementing a protocol over serial ports on Linux. The protocol is based on a request answer scheme so the throughput is limited by the time it takes to send a packet to a device and get an answer. The devices are mostly arm based and run Linux >= 3.0. I'm having troubles reducing the round trip time below 10ms (115200 baud, 8 data bit, no parity, 7 byte per message).
What IO interfaces will give me the lowest latency: select, poll, epoll or polling by hand with ioctl? Does blocking or non blocking IO impact latency?
I tried setting the low_latency flag with setserial. But it seemed like it had no effect.
Are there any other things I can try to reduce latency? Since I control all devices it would even be possible to patch the kernel, but its preferred not to.
---- Edit ----
The serial controller uses is an 16550A.
Request / answer schemes tends to be inefficient, and it shows up quickly on serial port. If you are interested in throughtput, look at windowed protocol, like kermit file sending protocol.
Now if you want to stick with your protocol and reduce latency, select, poll, read will all give you roughly the same latency, because as Andy Ross indicated, the real latency is in the hardware FIFO handling.
If you are lucky, you can tweak the driver behaviour without patching, but you still need to look at the driver code. However, having the ARM handle a 10 kHz interrupt rate will certainly not be good for the overall system performance...
Another options is to pad your packet so that you hit the FIFO threshold every time. It will also confirm that if it is or not a FIFO threshold problem.
10 msec # 115200 is enough to transmit 100 bytes (assuming 8N1), so what you are seeing is probably because the low_latency flag is not set. Try
setserial /dev/<tty_name> low_latency
It will set the low_latency flag, which is used by the kernel when moving data up in the tty layer:
void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
spin_unlock_irqrestore(&tty->buf.lock, flags);
if (tty->low_latency)
flush_to_ldisc(&tty->buf.work);
else
schedule_work(&tty->buf.work);
}
The schedule_work call might be responsible for the 10 msec latency you observe.
Having talked to to some more engineers about the topic I came to the conclusion that this problem is not solvable in user space. Since we need to cross the bridge into kernel land, we plan to implement an kernel module which talks our protocol and gives us latencies < 1ms.
--- edit ---
Turns out I was completely wrong. All that was necessary was to increase the kernel tick rate. The default 100 ticks added the 10ms delay. 1000Hz and a negative nice value for the serial process gives me the time behavior I wanted to reach.
Serial ports on linux are "wrapped" into unix-style terminal constructs, which hits you with 1 tick lag, i.e. 10ms. Try if stty -F /dev/ttySx raw low_latency helps, no guarantees though.
On a PC, you can go hardcore and talk to standard serial ports directly, issue setserial /dev/ttySx uart none to unbind linux driver from serial port hw and control the port via inb/outb to port registers. I've tried that, it works great.
The downside is you don't get interrupts when data arrives and you have to poll the register. often.
You should be able to do same on the arm device side, may be much harder on exotic serial port hw.
Here's what setserial does to set low latency on a file descriptor of a port:
ioctl(fd, TIOCGSERIAL, &serial);
serial.flags |= ASYNC_LOW_LATENCY;
ioctl(fd, TIOCSSERIAL, &serial);
In short: Use a USB adapter and ASYNC_LOW_LATENCY.
I've used a FT232RL based USB adapter on Modbus at 115.2 kbs.
I get about 5 transactions (to 4 devices) in about 20 mS total with ASYNC_LOW_LATENCY. This includes two transactions to a slow-poke device (4 mS response time).
Without ASYNC_LOW_LATENCY the total time is about 60 mS.
With FTDI USB adapters ASYNC_LOW_LATENCY sets the inter-character timer on the chip itself to 1 mS (instead of the default 16 mS).
I'm currently using a home-brewed USB adapter and I can set the latency for the adapter itself to whatever value I want. Setting it at 200 µS shaves another mS off that 20 mS.
None of those system calls have an effect on latency. If you want to read and write one byte as fast as possible from userspace, you really aren't going to do better than a simple read()/write() pair. Try replacing the serial stream with a socket from another userspace process and see if the latencies improve. If they don't, then your problems are CPU speed and hardware limitations.
Are you sure your hardware can do this at all? It's not uncommon to find UARTs with a buffer design that introduces many bytes worth of latency.
At those line speeds you should not be seeing latencies that large, regardless of how you check for readiness.
You need to make sure the serial port is in raw mode (so you do "noncanonical reads") and that VMIN and VTIME are set correctly. You want to make sure that VTIME is zero so that an inter-character timer never kicks in. I would probably start with setting VMIN to 1 and tune from there.
The syscall overhead is nothing compared to the time on the wire, so select() vs. poll(), etc. is unlikely to make a difference.