Starting from:

$25

CPEN412 -  Microcomputer Systems Design -Assignment 5 - Solved

 Microcomputer Systems Design - Assignment 5

              



 
Introduction:

 

EEProm is another type of memory common in microcomputer system because, unlike Flash, it allows byte-by-byte erasing and programming so is useful when storing configuration data, setup tables etc. ADCs and DAC’s are also common for interacting with the analog world.

 

For low to moderate speed systems, using EEProm and ADC/DACs with a serial interface is more common than a parallel interface as it results in physically smaller chips with fewer pins. As we saw in Lab 3, SPi is a common serial interface, and indeed you can get all the above chips with a SPi interface, but for this lab, we will use chips with an IIC (or I2C) serial interface which will of course require an IIC controller.

 

For this assignment, we are going to interface an IIC serial bus controller to our 68k system, fix it in the memory map of the system and then use it to control two IIC peripheral chips given to you by your instructor.  These chips are:-



A 128k byte EEProm – Microchip part # 24AA1025 as shown below (in surface mount form). The chip mailed out to you will have DIP packaging with longer breadboard friendly legs. MAKE SURE you identify it correctly as your Instructor has supplied several 8 pin DIP chips and the writing on them is very small. Use a cell phone camera to zoom in on it if required. 

Make sure you identify Pin 1 on the device and wire up the power correctly. Triple check your connections. If you blow up the device, you may not be able to get another before the assignment deadline.


  

 

 

An ADC/DAC converter (based on a PCF 8591 chip) soldered to a tiny PCB with three sensors (Potentiometer, Light and Temperature), plus an LED which can be controlled by the DAC e.g. PWM techniques or Sine, Triangle waveforms etc.). 

These can be seen along the top of the image below from left to right. The 2-pin jumper links should be left in place to connect the PCF 8591 chip to these sensors and outputs. Identify Vcc and Ground and again triple check the power connections.
 

 

 

 

Connections

The PCF 8591 has 4 ADC channels and 1 DAC channel arranged as described below. These assume the 4 jumpers shown on the right of the PCB are in place.

 

1. AN0: External analog source (remove jumper)

2. AN1: On board potentiometer to supply a variable voltage.

3. AN2: On board thermistor to measure temperature

4. AN3: On board photo resistor to measure light intensity

5. OUT: A RED LED which can be driven by the D/A output. 

 

You will also notice the SCL/SDA lines required by the IIC bus and the Signal A0 which can be used to assign the device a slave address. The PCF 8591 chip actually has pins labelled A0, A1 and A2 that would in theory allows up to 8 of these devices to exist in a system, but only A0 is brought out for configuration.

 

The A1 and A2 pins of the PCF 8591 chip have been wired to logic ‘0’ on the PCB, so only two of these modules could hang off the same IIC controller, one with A0=0, the other with A0 = 1. Very little documentation is available on the PCB itself but 99% of what’s important is the PCF 8591 chip itself. 

 

Data sheets for the EEProm and PCF 8591 chips are on Canvas so that you can understand the protocol of commands you need to write/talk to them to get device to work – study it carefully. The documentation for the ADC/DAC module is available Here

 

You are free to use whatever version of the 68k system you currently have to carry out this assignment, i.e. either the 25Mhz non-cache system (preferred) or the 40/45Mhz system with a cache (will still be OK, but because the timing on the cache is tight, the Quartus Fitter may have difficulty placing and routing to meet those timings – you probably experienced this during Lab 4). If you use the Cache version some simple timing information below will change due to higher clock frequency.



The IIC controller itself is already written in VHDL and has been downloaded from OpenCores.org. It consists of 3 VHDL files which need to be added to your Quartus project. A data sheet for the controller and the 3 VHDL files are posted on Canvas alongside this assignment. The datasheet gives details of the electrical interface to the outside world (our 68k processor in this case) as well as how to program it, i.e. what registers are inside that we can read/write to with our 68k processor to control the IIC bus and talk to the above peripheral chips.

 

The IIC controller chip itself is designed to be "Wishbone Bus" compliant. Wishbone is an open standard parallel computer bus designed specifically for use inside FPGAs. It's an alternative to Altera's own proprietary “Avalon Bus" and ARMs “AMBA/AXi bus”- i.e. same intent and purpose. 

It's not too different in principle to the asynchronous bus the 68000 uses, i.e. it requires an acknowledge with each transfer and it is relatively easy to interface a Wishbone compliant chip to the 68k system we are building, as shown below.

 

The circuit below shows what the IIC interface will look like when integrated into the IIC_SPI_Controller schematic. You should already have an SPI controller here from Lab 3, so add the circuitry below for the IIC controller and make suitable adjustments to the address decoder (see later) to bring out a new IIC enable signal (keep the SPI enable signal and circuitry you already have).

 

 

  

Note input signal to address decoder above should be AS_L not UDS_L. 
Signal UDS_L is not required (my mistake)

 

Note that a tri-state output buffer has been added to the DataOut bus from the chip which is only enabled when the 68k reads from the IIC controller chip. The circuit also has a secondary address decoder - see above top left. You can write the HDL for this. 

Note that the address decoder is enabled whenever the CPU talks to the IO space, i.e. when IOSelect is active High/Logic 1 and AS_L is logic 0. This signal comes from the primary address decoder on the top level schematic for the 68k system, so use that.  

 

IOSelect is active for all 68k read/writes in the address range hex 0040 0000 - 0040 FFFF. Your secondary decoder thus only needs to decode the lower 64k of this space when IOSelect is active (i.e. address lines A15-A1). 



You can chose any address space you like for your IIC Controller but in the example above, the address range 00408000 – 0040800F has been chosen to avoid conflict with any other IO devices that are already in the system like the LEDs, Timers, LCD display and Switch inputs, so stick to this address. 

 

This gives a 16 byte range in the memory map for the IIC controller which is sufficient, as it only has 7 internal byte wide registers and some of those share the same address. Access to shared registers is performed by the chip on the basis of whether the 68k is reading or writing to the controller, so in fact all 7 registers actually only occupy a 4 byte space - (see Page 7 in the IIC controller user manual). Note however that the registers appear as alternate bytes in the 68k memory map since the IIC controller has an 8 bit data bus and is connected to d8-d15 on the 68k - as we saw in Assignment 3 with the SPI flash chip.

 

The illustration below shows a dump of memory at the addresses occupied by the IIC controller. This was performed using the DU command – Dump Memory, of the debug monitor. 

 

You can clearly see the values FF for all ODD addresses (i.e. addresses that the IIC controller will not respond to as it is connected to the upper half of the 68k’s data bus only) and other values corresponding to the values read from internal IIC controller registers at EVEN addresses (note some of the register values shown below had been programmed or modified with the debug monitor M command) to write values to them. These may set back to FF after a hardware reset. 

 

  

 

To use the debug monitor to write/read some value to the IIC controller registers (just to experiment), use the M command as shown below. Note how writing a value to odd addresses always fails as the IIC controller is connected to the upper half of the 68k’s data bus which corresponds to even byte addresses. 

 

Note also that some writes to valid address also APPEAR to fail, e.g. 00408006. This is because that address corresponds to two separate registers inside the IIC controller the TX and RX registers. When the 68k writes to that address it will write to the TX register, however, the debugger verifies the write by reading back the data it wrote and comparing the two results. During that read, it will however read back the value of the RX registers – that’s why it only appears to fail.

 

 

 

DTACK generation for the IIC controller

 

A 68k Dtack signal is automatically generated for any access made in the IO space 
[0040 0000 - 0040 FFFF] by the default dtack generator on the top level 68k system schematic, so you won’t have to modify that.

 

The secondary address decoder above should provide a wb_stb (an active high wishbone strobe) signal to the chip when the 68k is addressing it - like a chip enable. Its data bus is 8 bits wide and you will have to map this (i.e. d0-d7 in and out from the IIC controller) to the 68k's data bus d8-d15. This means the registers within the device can be read/written to by the 68k at even addresses (e.g. base address + 0, base address + 2 etc.).

 

You will notice that the IIC bus signals SCL/SDA signals are bi-directional since IIC devices can read and write to them. To get Quartus to synthesize open drain outputs, an open drain driver circuit has been added (see circuit previously). The VHDL for this is given below and comes from the IIC controller data sheet, but that had a few minor typos which are corrected here. Open drains are synthesised by Quartus if it detects that you only ever assign '0' or 'Z' (tri-state) values to an output, i.e. you never assign a '1'.

 

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_arith.all;

 

entity SCL_SDA_OPEN_DRAIN_DRIVER is

            port (

                        -- i2c lines

                        scl_pad_i     : out  std_logic;        -- i2c clock line input

                        scl_pad_o     : in  std_logic;          -- i2c clock line output

                        scl_padoen_o  : in  std_logic;      -- i2c clock line output enable, active low

                        sda_pad_i     : out  std_logic;       -- i2c data line input

                        sda_pad_o     : in std_logic;         -- i2c data line output

                        sda_padoen_o  : in std_logic;      -- i2c data line output enable, active low

                        

                        SCL : inout std_logic ;

                        SDA : inout std_logic

            );

end entity SCL_SDA_OPEN_DRAIN_DRIVER;

 

architecture structural of SCL_SDA_OPEN_DRAIN_DRIVER is

begin

            SCL <= scl_pad_o when (scl_padoen_o = '0') else 'Z';

            SDA <= sda_pad_o when (sda_padoen_o = '0') else 'Z';

            

            scl_pad_i <= SCL;

            sda_pad_i <= SDA;

end architecture;

 

Add the circuit to the Top level Schematic

Create a new symbol for the IIC controller logic and then you can paste this onto the top level 68k system schematic and make the connects to the 68k signals and outside world (see below). Note the connections may already be set up in the pin planner – Check !!!.

 

 

 
Bring the SCL and SDA signals to the outside world

 

Before we can connect our controller to the ADC and EEProm IIC chips via a breadboard, we have to bring the SCL and SDA pins out to the GPIO_0 connecter (one of the 2 x 40 pin connectors on the r.h.s. of the DE1 board). GPIO_0 is the left or inner-most connector. The right most one GPIO_1 may already have things wired to it so we won't use that.

 

In the pin planner, wire SCL to pin AJ17 and SDA to AJ16. These correspond to signals A8 and A9 on the GPIO_O connector shown below which is pin 9 and 10 on the actual connector (i.e. 5 pins down from the top on the left and right hand side). You'll notice and 5v and Ground pins are immediately beneath which is useful and can be used to power our IIC chips.

 

  

 

You can now bring out these signals to a breadboard where you can plug in your chips.

 

IMPORTANT you will have to add pull-up resistors for the SCL and SDA signals on your breadboard to ensure that a logic 1 can be created on those signals since open drain outputs cannot actively generate/drive a logic 1 (only a logic 0). Your instructor will give you 2 resistors of 4.7k ohms for this purpose (the exact resistor value is not important but affects rise/fall times of signals and power consumption).

 

Testing your IIC Controller Interface. 



Note: It’s a good idea to verify that your hardware interface above works before trying to write any software to drive the controller. One simple way is to use the memory examine and change command  (‘M’ + Address) built into the debug monitor of the 68k system, to write/read some values to/from the registers inside the IIC controller (see earlier). If you can write a value to a register and read the same value back then that’s a pretty good indication that your chip has interfaced correctly to the 68k. 

The data sheet for the IIC controller Page 7 explains what registers exist, whether they are read only or write only (or both) – but be careful two registers may share the same address such as the Transmit/Receive registers and also the Control/Status register. So writing to them will not always give you same value when you read it back (the debug monitor may give an error when you write a value to one of these registers since it tries to read back and verify what was written - just ignore that)

 

Note also they will be offset by 1 byte as they only appear on even addresses in the 68k’s address map due to the fact that the IIC controller is an 8 bit peripheral connect to only one half of the 68k’s data bus – just like the set up we had when we interfaced to the Flash chip in Assignment 2.

 

Lastly make sure you connect the pull-up resistors that tie the SCL and SDA lines to logic ‘1’ before using the debug monitor to read/write to the controller, otherwise the chip might hang if it does not see a logic ‘1’ on those signal (i.e. it might think the bus is already in use without a logic 1 – remember IIC is multi-master capable).

 

Testing your IIC controller 

If possible use the debugger is try to program the registers in the IIC controller "by Hand" (using the debug monitor - M command) and get it to transmit something so that you can see a waveform on the SDA and SCL lines with an oscilloscope (if one is available). This will help you verify your chip is working and understand what data to write to the chip to get it to transmit something (i.e. understand the data sheet).

 

The ADC/DAC and EEProm Data Sheets

As mentioned previously, the data sheets for EEProm and ADC/DAC chips are posted on Canvas. These will explain the protocol of IIC commands that you have to give your IIC controller above to control/read/write to the peripheral chip. This in turn requires that you write ‘C’ code to talk to the IIC controller which in turn will talk to the IIC chips (ADC/DAC and EEProm).

 

IMPORTANT: read section 8.5 and 8.6 of the ADC/DAC chip data sheet as these sections explain how to wire the chip to use the internal oscillator (for the successive approximation ADC) and how to wire the analog reference voltage. You will also need to wire the A0 signal on the tiny PCB to match whatever IIC slave address you broadcast (read lecture on IIC Bus to understand what is meant by this)

 

 

Hints for writing C code to drive IIC controller and ADC/EEProm chips

 

Don't forget to initialise and enable the IIC controller. Set it up for no interrupts and set the clock frequency for 100Khz (see the equation in the IIC controller data sheet - Page 7) - Connect the controller to the 25MHz clock (or 45Mhz if using the version with the Cache) that the CPU uses.
 

Before writing anything over the IIC bus make sure device is ready (i.e. TX register has written previous command). Check the status register TIP bit (bit 1) to see when transmit has finished. Also don’t forget to wait for the ACK back from the slave after each write to it.

To write data, put the data to be transmitted into TX register then write something to the command register that indicates that you want to write. If you want to generate a start or stop condition with each byte written, set the STA or STO bits in the command register when you write to it, ditto, clear the ACK bit if you want to generate an acknowledge when reading data back from the slave. 
 

Set the RD or WR bit in the command register to indicate the direction of transfer (from master to slave - i.e. write to slave, or from slave to master - i.e. slave read). Mix and match the bits you need using AND/OR bit operations. 
 

 

 

Once you have written anything over IIC bus to slave, always wait for an acknowledge (check status register bit RxACK – bit 7).
 

To transmit something over IIC bus to a slave device, write the data to be transmitted to the TX register (see note 1 above though), then write to the command register. The command register allows you to specify the type of IIC operation to perform. Set RD bit if you want to READ from slave, set WR bit if you want to WRITE to Slave. Set STA or STOP bit if you want to generate start or stop conditions when reading/writing bytes over IIC. Set ACK bit when choosing a read from a Slave, so the IIC controller will acknowledge back to the slave that data has been received. Set IACK bit to clear any pending interrupt flag (even though we won’t use interrupts) when writing any command.
 

To start a write to say the EEProm, write a slave address (and set bit 0 of the data to be transmitted to 0 – indicating that you are writing an address to the slave). Remember to generate a start condition and also to set bit 1 and bit 2 to the A0/A1 values wired for the EEProm and set bit 3 to indicate which of the two 64k byte blocks you are writing to (B0)  and set bits 7-4 to  “1010” – See section 5 on device addressing for the EEProm chip.

Next write 2 bytes which correspond to the 2 byte internal (64k) address inside the Chip/Block, then write the data to be stored at that address (and generate a stop condition with that last byte) – again see note 1 for all these bytes that you write.
 

To start a read from the EEProm write a slave address (and set bit 0 of the data to be transmitted to 0 – for a write to slave operation), along with a start condition. Then write 2 bytes which correspond to the 2 internal address inside the chip (see note 1 again), then send a repeated start condition and set RD bit and ACK bit in command register (so controller will send acknowledge to slave after a byte is read), set stop bit (so only 1 byte is read) and don’t forget to set IACK bit to clear any pending interrupt flag (even though we won’t use interrupts) when reading data.

When data is received from slave, you can find it in the IIC RX register. You will have to poll the IIC controller to determine when the data has been read from the slave. This can be done by checking the “IF” flag in the status register (bit 0), when it is equal to ‘1’, the data has been received. Remember to clear this with each byte read so you will know when the next byte has arrived. Remember, if the slave device does not get an ACK from the IIC controller when it is sending the controller data (i.e. the CPU is reading from the slave), it will abandon further transmission.
 

 

 

What do you have to do for this assignment?

 

Write a C program to initialise and communicate with the IIC controller and that it in turn can communicate with the peripheral device you have been given.
Demonstrate that you can control the peripheral via the IIC controller in ways that are appropriate for it e.g. read/write bytes or blocks of data for an EEProm, and also read write analog data for the ADC/DAC etc. 
 



 

Part A: EEProm Operation

Along with the functions below, write code to put together an application to demo the EEProm operation, i.e. a main() plus some demo code to exercise the functions below

 

1.      A function to Read a Single Byte from the EEProm from a specified starting address anywhere in the chip                                                                  10 Marks 

2.      A function to Write a Single Byte to the EEProm from a specified starting 
address anywhere in the chip                                                              10 Marks

3.      A function to Read a block of any specified size up to 128K bytes starting at any address in the EEProm chip (do NOT write this function to just make repeated calls to the function 1 above – create a speed optimised version to get the data as fast as possible without having to broadcast a new physical IIC address for each byte, i.e. use the page read operation.                                                20 Marks

4.      A function to Write a specified sized block of data up to 128K bytes starting at any address in the EEProm chip (again, do NOT write this function to just make repeated calls to the function 2 above – create a speed optimised version to write the data as fast as possible without having to broadcast a new physical IIC address for each byte (e.g. page write mode). For testing, use incrementing 8 bit values as your data.                                                                            20 Marks


Points 3 and 4 above requires careful handling since the chip is physically organised as 2 x 64Kbyte chips packaged inside the same physical device, so a different IIC address is required to access the lower 64k vs. the upper 64k halves (See address B0 in data sheets section 5), i.e. you cannot just treat it as a single 128k byte device. This will be tricky if you cross the 64k boundary during a read or write operation.

Just remember that the device can cope with a burst of 128 bytes during a page write operation after which a new internal address will be needed to avoid address “wrap around” (see page write operation in the EEProm data sheet).

 

The device can also cope with indefinite sequential reads (without a stop condition or the need to transmit a new physical or internal address) within a given 64k block (such 00000 – 0FFFF) and also (10000 – 1FFFF), so be careful during reading if you straddle that 64k boundary (for example internal address 0FFFF will not automatically wrap to 10000, in fact it will wrap to 00000. Likewise address 1FFFF will wrap to address 10000, not 00000). 

This means you will need to generate a new physical + Internal address when crossing a 64k block boundary. (See sequential read operation in the EEProm data sheet).

                                                                                  

 

 

 

Part B: ADC/DAC Operation

Along with the functions below, write code to put together an application to demo the ADC/DAC operation, i.e. a main() plus some demo code to exercise the functions below.

 

5.      Ability to generate a Waveform out of the DAC on the ADC/DAC chip by writing continuous (i.e. streaming) data with no stop condition to it. Use this to control the LED to create some visual effects. If you have an oscilloscope – connect it and capture the waveform as part of your video submission.            20 Marks

 

6.      Ability to read an analog input from any given ADC channel and from that read/display the values of the 3 sensors on the PCB module       20 Marks

 

Note the ADC operation makes use of the internal DAC, so you cannot have both ADC and DAC operation simultaneously; it’s one or the other. Also, do not connect any voltage generator to the ADC (you don’t want to blow up your DE1) just use the sensors on the PCB e.g. potentiometer. Just display the reading in Hex or decimal, there is no real need to convert to volts.


More products