Interestingly, very similar VHDL written for the CPLD LED Fading article can be used for this project. The two key parts of the VHDL code are:
-ADC Input Trigger
-PWM Pulse Generation
It might sound difficult, but actually getting the digital data from the A-to-D converter is as simple as sending a trigger pulse, waiting a few microseconds and then pulling the digital input into the FPGA/CPLD.
ADC Input VHDL
------------« Begin Code »------------
PROCESS(CLK) variable cnt: integer range 0 to 500000; BEGIN IF(RISING_EDGE(CLK))THEN ----------------------------------------- ---- Pulse The MAX150 ADC To Update The Digital Output ------ ----------------------------------------- IF(cnt = 100000)THEN ADC_ENABLE <= '1'; cnt := cnt + 1; --MAX150A Is Active Low --Hold WR* Low For Wayyyy Longer Than Necessary ELSIF(cnt = 200000)THEN ADC_ENABLE <= '0'; cnt := cnt + 1; ELSIF(cnt = 300000)THEN ADC_ENABLE <= '1'; cnt := cnt + 1; --Pull The Data In After At Least 2-3uS ELSIF(cnt = 400000)THEN adc_value <= ADC_INPUT; cnt := 0; ELSE cnt := cnt + 1; END IF; END IF; END PROCESS;
------------« End Code »------------
On the other side of things, creating the PWM output is a little more tricky. We'll use a period of 512 clock cycles and vary the PWM pulse by 255 from the center of 256. This will all us to get up to 99%[on]/1% off and down to 1%[on]/99%[off] for the PWM pulses. It's important to note that the PWM signal outputs in a logrithmic fashion because of leftover code from the LED fading article.
PWM Pulse Generation
------------« Begin Code »------------
--A Much Better Way To Create PWM Using VHDL --PWM Going To The Motor: Differential Signal P IF(adc_value = x"00")THEN LED_OUTPUT(9) <= '1'; LED_OUTPUT(8) <= '0'; LED_OUTPUT(7) <= '1'; LED_OUTPUT(6) <= '0'; LED_OUTPUT(5) <= '1'; LED_OUTPUT(4) <= '0'; LED_OUTPUT(3) <= '1'; LED_OUTPUT(2) <= '0'; LED_OUTPUT(1) <= '1'; LED_OUTPUT(0) <= '0'; ELSE --PWM Going To The Motor: Differential Signal N IF(pwm_cnt = 257-conv_integer(adc_value))THEN pwm_cnt := pwm_cnt + 1; LED_OUTPUT(9) <= '0'; LED_OUTPUT(8) <= '1'; LED_OUTPUT(7) <= '0'; LED_OUTPUT(6) <= '1'; LED_OUTPUT(5) <= '0'; LED_OUTPUT(4) <= '1'; LED_OUTPUT(3) <= '0'; LED_OUTPUT(2) <= '1'; LED_OUTPUT(1) <= '0'; LED_OUTPUT(0) <= '1'; --When 257 is reached, Reset everything. ELSIF(pwm_cnt = 257)THEN pwm_cnt := 0; LED_OUTPUT(9) <= '1'; LED_OUTPUT(8) <= '0'; LED_OUTPUT(7) <= '1'; LED_OUTPUT(6) <= '0'; LED_OUTPUT(5) <= '1'; LED_OUTPUT(4) <= '0'; LED_OUTPUT(3) <= '1'; LED_OUTPUT(2) <= '0'; LED_OUTPUT(1) <= '1'; LED_OUTPUT(0) <= '0'; ELSE pwm_cnt := pwm_cnt + 1; END IF; END IF;
------------« End Code »------------
When these two input/output functions are combined together in a single VHDL entity, they create the DC motor control system that we desire. So let's go see it in action!