pia-468x60

pia-728x90

Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Monday, February 5, 2024

XC95108 VHDL Parallel to Serial Shift Registers and Arduino Example

A parallel to serial shift register is useful for microprocessor digital inputs extending. For instant a keypad input for printer for photocopier machine. There are many off-the-shelf parallel to serial shift register chips, especially the SN74HC165.

XC95108 VHDL Parallel to Serial Shift Registers and Arduino Example
Hardware Testing

Using a programmable logic device we can design this kind of chip with customizable operations, and the numbers of I/O. This job could be done with a CPLD chip and its design tool, VHLD, Verilog code, or even schematic design tool.

XC95108 VHDL Parallel to Serial Shift Registers and Arduino Example
Running Arduino Program and the XC95108

In this example, I use an XC95108 CPLD to design a parallel to serial converter chip. VHDL code is preferred for this design. This design contains,

  • Clock (CLK) input,
  • LOAD input to latch data from an 8-bit digital input to the internal register,
  • Serial Data Out (DOUT) that shift data serially at the rising edge of input clock,
  • Digital Input (D) is an 8-bit data input.

The overall process requires 9 clock cycles. At the first clock, data will be read and latched into an internal register, then the 8-bit serial data shifting out will be processed.

  1. ----------------------------------------------------------------------------------
  2. -- Company:
  3. -- Engineer:
  4. --
  5. -- Create Date: 08:31:41 02/03/2024
  6. -- Design Name:
  7. -- Module Name: parallel_serial_2 - Behavioral
  8. -- Project Name:
  9. -- Target Devices:
  10. -- Tool versions:
  11. -- Description:
  12. --
  13. -- Dependencies:
  14. --
  15. -- Revision:
  16. -- Revision 0.01 - File Created
  17. -- Additional Comments:
  18. --
  19. ----------------------------------------------------------------------------------
  20. library IEEE;
  21. use IEEE.STD_LOGIC_1164.ALL;
  22.  
  23. entity parallel_serial_2 is
  24. Port ( CLK : in STD_LOGIC;
  25. LOAD : in STD_LOGIC;
  26. DOUT : out STD_LOGIC;
  27. D : in STD_LOGIC_VECTOR (7 downto 0));
  28. end parallel_serial_2;
  29.  
  30. architecture Behavioral of parallel_serial_2 is
  31. SIGNAL REG: STD_LOGIC_VECTOR(7 DOWNTO 0);
  32. begin
  33. PROCESS(CLK,LOAD)
  34. BEGIN
  35. IF(CLK'EVENT AND CLK='1') THEN
  36. IF(LOAD='1') THEN REG<=D;
  37. ELSE REG<=REG(6 DOWNTO 0)&'0'; END IF;
  38. END IF;
  39. END PROCESS;
  40. DOUT<=REG(7);
  41. end Behavioral;
  42.  
  43.  

You can use the FloorPlan I/O tool in the ISE Design Suite to assign its I/O pins. On the XC95108 CPLD Prototype Board, I set the I/O as follow.

  1. #PACE: Start of Constraints generated by PACE
  2.  
  3. #PACE: Start of PACE I/O Pin Assignments
  4. NET "CLK" LOC = "P50" ;
  5. NET "D<0>" LOC = "P48" ;
  6. NET "D<1>" LOC = "P47" ;
  7. NET "D<2>" LOC = "P46" ;
  8. NET "D<3>" LOC = "P45" ;
  9. NET "D<4>" LOC = "P44" ;
  10. NET "D<5>" LOC = "P43" ;
  11. NET "D<6>" LOC = "P41" ;
  12. NET "D<7>" LOC = "P40" ;
  13. NET "DOUT" LOC = "P52" ;
  14. NET "LOAD" LOC = "P51" ;
  15. #PACE: Start of PACE Area Constraints
  16.  
  17. #PACE: Start of PACE Prohibit Constraints
  18.  
  19. #PACE: End of Constraints generated by PACE
  20.  

The Arduino is very popular for most of electronics projects. I use an Arduino Uno to read the data from this chip.

  1.  
  2.  
  3. const char clockPin= 13;
  4. const char Enable = 10;
  5. const char dataPin=12;
  6.  
  7. uint8_t incoming=0,oldData;
  8.  
  9. void setup() {
  10. Serial.begin(9600);
  11. Serial.println("Arduino ShiftIn And XC95108 Parallel To Serial Converter.");
  12. pinMode(clockPin,OUTPUT);
  13. pinMode(Enable,OUTPUT);
  14. pinMode(dataPin,INPUT);
  15. digitalWrite(clockPin,LOW);
  16. digitalWrite(Enable,LOW);
  17. }
  18.  
  19. void loop() {
  20. digitalWrite(Enable,HIGH);
  21. digitalWrite(clockPin,LOW);
  22. digitalWrite(clockPin,HIGH);
  23. digitalWrite(Enable,LOW);
  24.  
  25. for(uint8_t i=0;i<8;i++){
  26. digitalWrite(clockPin,LOW);
  27. if(digitalRead(dataPin)==1) incoming|=(1<<(7-i));
  28. else incoming&=~(1<<(7-i));
  29. digitalWrite(clockPin,HIGH);
  30. }
  31. if(incoming!=oldData){
  32. Serial.println("Received 8-Bit HEX Data: 0x" + String(incoming,HEX));
  33. Serial.println("Received 8-Bit BIN Data: 0b" + String(incoming,BIN));
  34. oldData=incoming;
  35. }
  36. // Serial.println(incoming,HEX);
  37. //Serial.println(incoming,BIN);
  38. delay(1500);
  39. }

Click here to download this example.



Monday, January 29, 2024

XC95108 Two-Digit 7-Segment Shift Registers VHDL Example

In previous post, I use the XC95108 to make a 16-bit LED shift registers. It's similar to the SNHC164 serial in parallel out shift registers chip. Using a CPLD and VHDL code we can customize any digital circuit. 

XC95108 Two-Digit 7-Segment Shift Registers VHDL Example
The Arduino Uno and the XC95108 CPLD Prototype Board 

Here I make another serial in parallel out shift registers chip that's similar to the SN74HC595. It's a two-digit 7-Segment display driver with SPI interface. It has the following I/O:

  • Reset (RST) input (active low)
  • Enable (EN) input for data latching
  • Serial Data In (MOSI)
  • Serial Clock In (SCK)
  • 7-Segment Digit 1 (LEDA)
  • and 7-Segment Digit 2 (LEDB).

The 7-Segment display is a two-digit 0.56" red common cathode display. The shift registers process is synchronize with the logic high level of serial clock input (SCK). Shift registers data are latched into the output LED ports at the high to low transition of the EN (Enable) pin.

  1. ----------------------------------------------------------------------------------
  2. -- Company:
  3. -- Engineer:
  4. --
  5. -- Create Date: 08:29:52 01/30/2024
  6. -- Design Name:
  7. -- Module Name: spi_7_2 - Behavioral
  8. -- Project Name:
  9. -- Target Devices:
  10. -- Tool versions:
  11. -- Description:
  12. --
  13. -- Dependencies:
  14. --
  15. -- Revision:
  16. -- Revision 0.01 - File Created
  17. -- Additional Comments:
  18. --
  19. ----------------------------------------------------------------------------------
  20. library IEEE;
  21. use IEEE.STD_LOGIC_1164.ALL;
  22.  
  23. -- Uncomment the following library declaration if using
  24. -- arithmetic functions with Signed or Unsigned values
  25. --use IEEE.NUMERIC_STD.ALL;
  26.  
  27. -- Uncomment the following library declaration if instantiating
  28. -- any Xilinx primitives in this code.
  29. --library UNISIM;
  30. --use UNISIM.VComponents.all;
  31.  
  32. entity spi_7_2 is
  33. Port ( RST : in STD_LOGIC;
  34. EN : in STD_LOGIC;
  35. SCK : in STD_LOGIC;
  36. MISO : in STD_LOGIC;
  37. LEDA : out STD_LOGIC_VECTOR (7 downto 0);
  38. LEDB : out STD_LOGIC_VECTOR (7 downto 0));
  39. end spi_7_2;
  40.  
  41. architecture Behavioral of spi_7_2 is
  42. SIGNAL REGA,REGB: STD_LOGIC_VECTOR(7 DOWNTO 0);
  43. begin
  44. PROCESS(SCK,RST,EN)
  45. BEGIN
  46. IF(RST='0') THEN REGA<=x"00"; REGB<=x"00";
  47. ELSIF(SCK'EVENT AND SCK='1') THEN
  48. -- REGISTER A
  49. REGA(0)<=MISO;
  50. REGA(1)<=REGA(0);
  51. REGA(2)<=REGA(1);
  52. REGA(3)<=REGA(2);
  53. REGA(4)<=REGA(3);
  54. REGA(5)<=REGA(4);
  55. REGA(6)<=REGA(5);
  56. REGA(7)<=REGA(6);
  57.  
  58. -- REGISTER B
  59. REGB(0)<=REGA(7);
  60. REGB(1)<=REGB(0);
  61. REGB(2)<=REGB(1);
  62. REGB(3)<=REGB(2);
  63. REGB(4)<=REGB(3);
  64. REGB(5)<=REGB(4);
  65. REGB(6)<=REGB(5);
  66. REGB(7)<=REGB(6);
  67.  
  68. END IF;
  69. -- INPUT DATA LATCH
  70. IF(EN'EVENT AND EN='1') THEN
  71. LEDA<=REGA; LEDB<=REGB;
  72. END IF;
  73. END PROCESS;
  74.  
  75. end Behavioral;
  76.  
  77.  

This VHDL circuit design uses 32 macro cells and 27 function blocks.

XC95108 Two-Digit 7-Segment Shift Registers VHDL Example
XC95108 CPLD Reports

I connect the CPLD to its on-board I/O devices (user constraint file) as follow. 

  1. #PACE: Start of Constraints generated by PACE
  2.  
  3. #PACE: Start of PACE I/O Pin Assignments
  4. NET "EN" LOC = "P54" ;
  5. NET "LEDA<0>" LOC = "P23" ;
  6. NET "LEDA<1>" LOC = "P24" ;
  7. NET "LEDA<2>" LOC = "P36" ;
  8. NET "LEDA<3>" LOC = "P34" ;
  9. NET "LEDA<4>" LOC = "P33" ;
  10. NET "LEDA<5>" LOC = "P21" ;
  11. NET "LEDA<6>" LOC = "P35" ;
  12. NET "LEDA<7>" LOC = "P37" ;
  13. NET "LEDB<0>" LOC = "P19" ;
  14. NET "LEDB<1>" LOC = "P20" ;
  15. NET "LEDB<2>" LOC = "P31" ;
  16. NET "LEDB<3>" LOC = "P25" ;
  17. NET "LEDB<4>" LOC = "P26" ;
  18. NET "LEDB<5>" LOC = "P17" ;
  19. NET "LEDB<6>" LOC = "P18" ;
  20. NET "LEDB<7>" LOC = "P32" ;
  21. NET "MISO" LOC = "P53" ;
  22. NET "RST" LOC = "P50" ;
  23. NET "SCK" LOC = "P52" ;
  24.  
  25. #PACE: Start of PACE Area Constraints
  26.  
  27. #PACE: Start of PACE Prohibit Constraints
  28.  
  29. #PACE: End of Constraints generated by PACE
  30.  

Using the Arduino Uno is common for most of electronics hobbyists. I use the Arduino SPI to send 7-Segment data to the XC95108 CPLD Prototype Board. This program will count up and down between 0 and 99.

  1. #include <SPI.h>
  2.  
  3. const char data_7[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  4. const char EN=10;
  5. volatile char data[2];
  6. volatile char count=0,up_down=0;
  7.  
  8. void setup() {
  9. SPI.begin();
  10. pinMode(EN,OUTPUT);
  11. digitalWrite(EN,LOW);
  12. }
  13.  
  14. void loop() {
  15. data[1]=data_7[count%10];
  16. data[0]=data_7[count/10];
  17. SPI.transfer(data,2);
  18. digitalWrite(EN,HIGH);
  19. delay(1);
  20. digitalWrite(EN,LOW);
  21. if(count==99) up_down=1;
  22. else if(count==0) up_down=0;
  23. if(up_down==1) count--;
  24. else if(up_down==0) count++;
  25. delay(250);
  26. }

The Arduino Uno must connects to the CPLD as follow.

  • Arduino Uno GND              -> XC95108 CPLD GND
  • Arduino Uno SCK (PIN13)   -> XC95108 CPLD (P52)
  • Arduino Uno MOSI (PIN11) -> XC95108 CPLD (P53)
  • Arduino Uno EN (PIN10)     -> XC95108 CPLD (P54)

Click here to download its source file.


Friday, December 15, 2023

XC9536 SPI Two-Digit Multiplexing Display Driver

In this VHDL example, I design a Serial Peripheral Interface (SPI) receiver circuit that can drive a two-digit multiplexing display. The SPI receiver module is similar to a SN74HC164 serial-in-parallel-out shift registers. This module contains two shift registers inside. These two registers connects individually connect to two output port that drive to a two-digit multiplexing display. 

XC9536 SPI Two-Digit Multiplexing Display Driver
I an Arduino Uno to send a serial data package over the SPI to the XC9536 CPLD on board. 







SPI module does not need internal clock source. But the multiplexing display module needs a clock source to drive its output display at a rate of 16 milliseconds. I use an NE555 square wave oscillator to create a timing signal with a frequency of 60Hz for multiplexing display driving.

This design contains two process one's for SPI receiver module, and another one's for multiplexing display driving. These two processes are concurrent so the multiplexing display process does not need to wait or get interrupted by the SPI receiving process.

  1. ----------------------------------------------------------------------------------
  2. -- Company:
  3. -- Engineer:
  4. --
  5. -- Create Date: 08:34:17 12/15/2023
  6. -- Design Name:
  7. -- Module Name: spi_display_2 - Behavioral
  8. -- Project Name:
  9. -- Target Devices:
  10. -- Tool versions:
  11. -- Description:
  12. --
  13. -- Dependencies:
  14. --
  15. -- Revision:
  16. -- Revision 0.01 - File Created
  17. -- Additional Comments:
  18. --
  19. ----------------------------------------------------------------------------------
  20. library IEEE;
  21. use IEEE.STD_LOGIC_1164.ALL;
  22.  
  23. -- Uncomment the following library declaration if using
  24. -- arithmetic functions with Signed or Unsigned values
  25. --use IEEE.NUMERIC_STD.ALL;
  26.  
  27. -- Uncomment the following library declaration if instantiating
  28. -- any Xilinx primitives in this code.
  29. --library UNISIM;
  30. --use UNISIM.VComponents.all;
  31.  
  32. entity spi_display_2 is
  33. Port ( OSC : in STD_LOGIC;
  34. RST : in STD_LOGIC;
  35. TEST: in STD_LOGIC;
  36. SCLK : in STD_LOGIC;
  37. SDAT : in STD_LOGIC;
  38. COM : out STD_LOGIC_VECTOR (1 downto 0);
  39. LED : out STD_LOGIC_VECTOR (7 downto 0));
  40. end spi_display_2;
  41.  
  42. architecture Behavioral of spi_display_2 is
  43. signal reg_0,reg_1 : STD_LOGIC_VECTOR(7 DOWNTO 0):=x"00";
  44.  
  45. begin
  46. -- SPI Receiver Block
  47. spi_receive: process(SCLK,RST)
  48. begin
  49. if(RST='0') then
  50. reg_0<=x"00"; reg_1<=x"00";
  51. elsif(SCLK'EVENT AND SCLK='1') then
  52. -- Serial Data Receive
  53. reg_0(0)<=SDAT;
  54. reg_0(1)<=reg_0(0);
  55. reg_0(2)<=reg_0(1);
  56. reg_0(3)<=reg_0(2);
  57. reg_0(4)<=reg_0(3);
  58. reg_0(5)<=reg_0(4);
  59. reg_0(6)<=reg_0(5);
  60. reg_0(7)<=reg_0(6);
  61.  
  62. reg_1(0)<=reg_0(7);
  63. reg_1(1)<=reg_1(0);
  64. reg_1(2)<=reg_1(1);
  65. reg_1(3)<=reg_1(2);
  66. reg_1(4)<=reg_1(3);
  67. reg_1(5)<=reg_1(4);
  68. reg_1(6)<=reg_1(5);
  69. reg_1(7)<=reg_1(6);
  70.  
  71. end if;
  72.  
  73. end process spi_receive;
  74.  
  75. -- Multiplexing Display Block
  76. display_multiplex: process(OSC,RST)
  77. variable ticks : INTEGER RANGE 0 TO 1:=0;
  78. begin
  79. if(RST='0') then ticks:=0; COM<="00"; LED<=x"00";
  80. elsif(OSC'EVENT AND OSC='1') then
  81. ticks:=ticks+1;
  82. if(test='1') then
  83. CASE ticks IS
  84. WHEN 0 => LED<=reg_0; COM<="01";
  85. WHEN 1 => LED<=reg_1; COM<="10";
  86. WHEN OTHERS => NULL;
  87. END CASE;
  88. else
  89. CASE ticks IS
  90. WHEN 0 => LED<=x"3F"; COM<="01";
  91. WHEN 1 => LED<=x"06"; COM<="10";
  92. WHEN OTHERS => NULL;
  93. END CASE;
  94. end if;
  95. end if;
  96. end process display_multiplex;
  97. end Behavioral;
  98.  
  99.  

As we can see the display has three digits but I can use only two digits because the XC9536 CPLD has limited resource. I can not add one more shift registers signal.

I assign all of its I/O pins as follow.

XC9536 SPI Two-Digit Multiplexing Display Driver
Xilinx PACE

Its user constraints file is automatically generated after the Xilinx PACE is saved.

#PACE: Start of Constraints generated by PACE
#PACE: Start of PACE I/O Pin Assignments
NET "COM<0>"  LOC = "P42"  ; 
NET "COM<1>"  LOC = "P43"  ; 
NET "LED<0>"  LOC = "P33"  ; 
NET "LED<1>"  LOC = "P34"  ; 
NET "LED<2>"  LOC = "P35"  ; 
NET "LED<3>"  LOC = "P36"  ; 
NET "LED<4>"  LOC = "P37"  ; 
NET "LED<5>"  LOC = "P38"  ; 
NET "LED<6>"  LOC = "P39"  ; 
NET "LED<7>"  LOC = "P40"  ; 
NET "OSC"  LOC = "P5"  ; 
NET "RST"  LOC = "P25"  ; 
NET "SCLK"  LOC = "P18"  ;
NET "SDAT"  LOC = "P19"  ;
NET "TEST"  LOC = "P26"  ; 
#PACE: Start of PACE Area Constraints
#PACE: Start of PACE Prohibit Constraints
#PACE: End of Constraints generated by PACE


I still use a Xilinx Parallel Cable III to program this CPLD.

XC9536 SPI Two-Digit Multiplexing Display Driver
Xilinx iMPACT Tools

We don't need to press the SPI serial data and serial clock manually. We just use an Arduino Uno board to send SPI data to this board. The Arduino uses three pins, MOSI, SCK, and reset to connect to the CPLD. 

The Arduino program below sends a counting variable ranging from 0 to 99 to the CPLD.

  1. #include<SPI.h>
  2.  
  3. void setup() {
  4. SPI.begin();
  5. pinMode(10,OUTPUT);
  6. digitalWrite(10,LOW);
  7. delay(1);
  8. digitalWrite(10,HIGH);
  9. SPI.transfer(0x3F);
  10. SPI.transfer(0x3F);
  11. delay(2500);
  12. }
  13.  
  14. int count=0;
  15. const char _7_SEG[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,};
  16. void loop() {
  17. SPI.transfer(_7_SEG[count%10]);
  18. SPI.transfer(_7_SEG[count/10]);
  19. delay(250);
  20. count++;
  21. if(count>99) count=0;
  22.  
  23. }

This program sends a random decimal number between 0 and 99 to the CPLD board.

  1. #include<SPI.h>
  2.  
  3. void setup() {
  4. SPI.begin();
  5. pinMode(10,OUTPUT);
  6. digitalWrite(10,LOW);
  7. delay(1);
  8. digitalWrite(10,HIGH);
  9. SPI.transfer(0x3F);
  10. SPI.transfer(0x3F);
  11. delay(2500);
  12. }
  13.  
  14. int myNumbers;
  15. const char _7_SEG[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,};
  16. void loop() {
  17. myNumbers=random(99);
  18. SPI.transfer(_7_SEG[myNumbers%10]);
  19. SPI.transfer(_7_SEG[myNumbers/10]);
  20. delay(500);
  21. }

Click here to download its source file.


Labels

ADC (11) Analog (15) Arduino (12) Atmega16 (19) Audio (2) AVR (20) CCS PICC (3) Charger (1) Cortex-M0 (1) Counter (10) CPLD (25) DHT11 (1) Digital I/O (23) Display (37) ds18B20 (1) EEPROM (2) Environment Sensor (2) esp8266 (2) Experiment Board (12) I2C (4) Interrupt (8) LCD (3) LDmicro (29) measurement and instrumentation (7) Microchip Studio (3) MikroC (1) One-Shot (3) OpAmp (1) PCB (32) PIC16 Microcontrollers (16) PIC16F877A (2) PIC16F887 MikroC (22) pic18 microcontrollers (2) PIC18F4550 (3) PLC (35) PWM (11) Regulator (1) RTC (3) Sensor (9) Shift Registers (5) SPI (5) Timer (34) UART (2) ultra-sonic sensor (1) USB (2) VHDL (21) xc8 (1) XC95108 (9) XC9536 (15) XC9572 (1) Xilinx (23) Xilinx ISE (22)