FPGA DC Motor Control

Program Download:

VHDL/Project Archive
FPGA_motor_control.vhd
FPGA_motor_control.zip

The Software
           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!