Jump to content
  • 0

Nexys 3/ PWM


shrestha

Question

hello all,  I am doing small class project. I would really appreciate if any one can help me with this. we are using SDK and we are trying to control servo which require PWM signal. I don't know how to generate PWM signal to control servo. I know it require two timers to do it. Thanks!!!

Link to comment
Share on other sites

8 answers to this question

Recommended Posts

I am guessing the project is to create a servo control signal with a microblaze processor and output something to the serial port.

 

I am not sure of the restrictions on the project but I would offload the servo PWM to FPGA fabric and change the compare value from the processor.

 

A super basic FPGA based PWM in verilog is something like:

 

always@ (posedge clk)

   if(counter < counter_max)

      counter <= counter + 1'b1;

 

assign PWM_out = (counter < compare_value(or slave_reg0)) ? 1'b1 : 1'b0;

 

Put that code into an AXI wrapper and read one of the slave registers as the compare value.

package the IP core and insert it into your EDK project.  

 

From SDK, write to the slave register using the built in Xilinx commands.

 

I have a great reference but it is for the zedboard and is on Vivado.  With that, I find microblaze and Zynq very similar and Vivado and ISE/EDK very similar.  He even has a PWM example!

 

http://svenand.blogdrive.com/archive/175.html#.VQth_fnF8qx

 

Good luck!

Link to comment
Share on other sites

Hi shrestha,

 

I would definitely recommend checking out this other post on our forum around post #10. Hamster (one of major contributors to our forum) does a fantastic job walking through how you would get a pwm signal up and running on an FPGA.

 

Let me know if you have any more questions.

 

Thanks,

JColvin

Link to comment
Share on other sites

Hey JColvin, i have done the motor and it works but servos works different than motor. I don't really know how to implement it? what i understood is servo has pulse width of 1 ms to 2ms, 1ms far left , 1.5 ms middle  and 2ms far right. Its pulse occur after every 20ms.so can i implement this?

Link to comment
Share on other sites

Hi Shestha, 

 

A few questions - what other resources do you have available - web sites, books, etc, so I can avoid going over the same stuff?

 

Do you have any test and measurement equipment available to you? (O'scope, logic analyser, multimeter...) 

 

If you are using SDK, does that implies that you are using a soft CPU core in the design? If you are using a soft CPU, then possibly using a timer peripheral is what you want to investigate.

 

If you are going to implement in VHDL, then there are a few questions.

 

1. What clock rate will you be using? 

 

2.. What precision of control do you need (e.g. just left and right, or 20 bits of accuracy)? What will you be using to input the desired position?

 

3. How many cycles is there in1ms, 1.5ms and 2ms,  20ms?

 

5. So if you had a counter running at your clock rate...

 

5a) What is the formula for when do you want to reset the counter back to zero (e.g. Fclk/50-1)

 

5b) What is the formula for when do you want to trigger the rising edge of the output?

 

5c) What is the formula for when do you want to trigger the falling edge of the output?

 

6) Can you make the answers of 5b and 5c more "binary friendly" (e.g. remove multiplication and division from the calculation)? 

 

If you can answer most of this then your design will be largely complete, and it just becomes an implementation problem...

Link to comment
Share on other sites

#define Port0_DATA        *(volatile int*) (XPAR_XPS_GPIO_0_BASEADDR)

#define Port0_DIRECTION  *(volatile int*) (XPAR_XPS_GPIO_0_BASEADDR+0x04)

#define Port1_DATA        *(volatile int*)(XPAR_XPS_GPIO_1_BASEADDR)

#define Port1_DIRECTION  *(volatile int*)(XPAR_XPS_GPIO_1_BASEADDR+4)

#define Port2_DATA         *(volatile int*) (XPAR_XPS_GPIO_2_BASEADDR)

#define Port2_DIRECTION    *(volatile int*) (XPAR_XPS_GPIO_2_BASEADDR+0x04)

#define Port2_GIER         *(volatile int*) (XPAR_XPS_GPIO_2_BASEADDR+0x11C)

#define Port2_IPIER     *(volatile int*) (XPAR_XPS_GPIO_2_BASEADDR+0x128)

#define Port2_IPISR      *(volatile int*) (XPAR_XPS_GPIO_2_BASEADDR+0x120)

 

#define SEVEN_SEG_DATA   *(volatile int*)(XPAR_DIGILENT_SEVSEG_DISP_BASEADDR)

 

#define LEDS_DATA *(volatile int*)(XPAR_LEDS_8BITS_BASEADDR)

#define LED_DIRECTION *(volatile int*)(XPAR_LEDS_8BITS_BASEADDR+4)

#define SWITCH_DATA *(volatile int*)(XPAR_DIP_SWITCHES_8BITS_BASEADDR)

#define SWITCH_DIRECTION *(volatile int*)(XPAR_DIP_SWITCHES_8BITS_BASEADDR+4)

 

#define INT_ISR *(volatile int*)(XPAR_INTC_0_BASEADDR)

#define INT_IPR *(volatile int*)(XPAR_INTC_0_BASEADDR+0x4)

#define INT_IER *(volatile int*)(XPAR_INTC_0_BASEADDR+0x8)

#define INT_IAR *(volatile int*)(XPAR_INTC_0_BASEADDR+0xC)

#define INT_MER *(volatile int*)(XPAR_INTC_0_BASEADDR+0x1C)

 

#define XPS_UART_RX_FIFO *(volatile*)(XPAR_XPS_UARTLITE_0_BASEADDR)

#define XPS_UART_TX_FIFO *(volatile*)(XPAR_XPS_UARTLITE_0_BASEADDR+0x04)

#define XPS_UART_STATUS *(volatile*)(XPAR_XPS_UARTLITE_0_BASEADDR+0x08)

 

 

#define TIMER00_CSR   *(volatile int*)(XPAR_XPS_TIMER_0_BASEADDR)

#define TIMER00_LOAD    *(volatile int*)(XPAR_XPS_TIMER_0_BASEADDR+0x04)

#define TIMER01_CSR    *(volatile int*)(XPAR_XPS_TIMER_0_BASEADDR+0x10)

#define TIMER01_LOAD    *(volatile int*)(XPAR_XPS_TIMER_0_BASEADDR+0x14)

 

#define TIMER10_CSR    *(volatile int*)(XPAR_XPS_TIMER_1_BASEADDR)

#define TIMER10_LOAD   *(volatile int*)(XPAR_XPS_TIMER_1_BASEADDR+0x04)

#define TIMER11_CSR    *(volatile int*)(XPAR_XPS_TIMER_1_BASEADDR+0x10)

#define TIMER11_LOAD    *(volatile int*)(XPAR_XPS_TIMER_1_BASEADDR+0x14)

 

#define INT_ISR       *(volatile int*)(XPAR_INTC_0_BASEADDR)

#define INT_IPR     *(volatile int*)(XPAR_INTC_0_BASEADDR+0x4)

#define INT_IER     *(volatile int*)(XPAR_INTC_0_BASEADDR+0x8)

#define INT_IAR     *(volatile int*)(XPAR_INTC_0_BASEADDR+0xC)

#define INT_MER      *(volatile int*)(XPAR_INTC_0_BASEADDR+0x1C)

 

#define ATOD_TRIGGER    *(volatile int*)(XPAR_PMOD_AD1_0_BASEADDR)

#define ATOD_DONE       *(volatile int*)(XPAR_PMOD_AD1_0_BASEADDR+0x04)

#define ATOD_DATA0     *(volatile int*)(XPAR_PMOD_AD1_0_BASEADDR+0x08)

#define ATOD_DATA1      *(volatile int*)(XPAR_PMOD_AD1_0_BASEADDR+0x0C)

 

 

#define count 10 //input how many increments to count

 

//define variables

int sum =0;

int array[count]; //define array[count]

int counter =0;

unsigned int average;

unsigned short data0;

 

unsigned short counter0;

unsigned short counter1;

unsigned short counterLED;

unsigned short timerflag;

unsigned short direction;

 

void print (char*str);

unsigned short data0;

 

char Get_Character(void);

void Put_Character(char ch);

void Put_String(char *string);

 

 

 

 

void delay_ms(unsigned short delay_time);

void delay_us(unsigned short delay_time);

 

int counter3;

 

void microblaze_0_Interrupt(void)__attribute__((interrupt_handler));

void microblaze_0_Interrupt(void){

int tmp;

tmp=INT_IPR;

if(tmp&XPAR_XPS_GPIO_2_IP2INTC_IRPT_MASK){//interrupt for port2

if(direction==1){//if clockwise

counter++;}//increment counter

else{//if counterclockwise

counter--;}//decrement counter

Port2_IPISR=Port2_IPISR; //clear port 2 interrupt

}

 

if(tmp&XPAR_XPS_TIMER_1_INTERRUPT_MASK){//interrupt for timer00

timerflag=1;//set timerflag to 1

counterLED++;

 

if (counterLED==500){

counter3++;

}

TIMER10_CSR=TIMER10_CSR; //clear timer 1 interrupt

}

INT_IAR=tmp;

}

 

 

int main()

{

init_platform();

counter=0; //initialize counter

counter3=0;

 

timerflag=0;//initialize timer0flag

direction = 0; //initialize direction

 

 

Port2_GIER = 0x80000000;

Port2_IPIER = 0x01;

 

ATOD_TRIGGER = 0x01;

 

    TIMER00_LOAD=2900; //timer00 PWM values

    TIMER01_LOAD=400; //timer01 PWN values

 

    TIMER00_CSR = 0x696;//pwm mode

    TIMER01_CSR = 0x696;//pwm mode

 

    TIMER10_LOAD=75000000/50; //changes the frequency(500Hz)

 

    TIMER10_CSR = 0x4F6;//set time10

    TIMER10_CSR = 0x4D6;

 

 

init_platform();

 

    while(1){

        if (counter<count){

 

        ATOD_TRIGGER = 0x01;

        while(ATOD_DONE!=0x01){

        }

        data0=ATOD_DATA0; //read data0 and save it

        array[counter] = data0; //save data0 as an array

        sum=sum+array[counter]; //sum is itself plus data0

        counter++; //increment counter

        TIMER01_LOAD=ATOD_DATA0;

        //Print Data0 to Serial Monitor

        xil_printf("1st data = %d  r", data0);

 

        ATOD_TRIGGER=0x00; //reset A/D converter

        }

        if (counter==count){

 

        counter=0;

        average = sum/count; //average

 

        //Print Data0 and Average to Serial Monitor

        xil_printf("1st data = %d   2nd data = %d r", data0, average);

 

    sum=0; //reset sum

        average=0; //reset average

        }

    }

    return 0;

 

}

 

 

void delay_us(unsigned short delay_time){

short i;

for(;delay_time>0;delay_time--){

for(i=0;i<5;i++){

}

}

}

 

 

char Get_Character(){

#define RX_FIFO_VALID_DATA 0x01

unsigned int status;

unsigned char ch;

status = 0x00;

status = XPS_UART_STATUS & RX_FIFO_VALID_DATA;

while(status != RX_FIFO_VALID_DATA){

status = XPS_UART_STATUS & RX_FIFO_VALID_DATA;

}

ch=XPS_UART_RX_FIFO;

return ch;

}

 

void Put_Character(char ch){

#define TX_FIFO_FULL 0x08

 

int status;

status = 0x00;

status = XPS_UART_STATUS & TX_FIFO_FULL;

while(status == TX_FIFO_FULL){

status = XPS_UART_STATUS & TX_FIFO_FULL;

}

XPS_UART_TX_FIFO = ch;

return;

}

 

void Put_String(char*string){

char ch;

while(1){

ch = *string;

if (ch == 0x00){

return;

}else{

Put_Character(ch);

string++;

}

}

}

 

​here is some code i tried. we are getting analog value form IR sensor which was in range of 400-2900. 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...