jim herd / FPGA_bus
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FPGA_bus.cpp Source File

FPGA_bus.cpp

00001 /*
00002  * FPGA_bus : 8-bit bi-directional bus between uP and FPGA
00003  */
00004 #include "mbed.h"
00005 #include "FPGA_bus.h"
00006 
00007 /** create a FPGA_bus object connecting uP to FPGA
00008  *
00009  * @param  nos_PWM      Number of PWM channels (default = 4)
00010  * @param  nos_QE       Number of Quadrature Encoder channels (default = 4)
00011  * @param  nos_servo    Number of RC servo channels (default = 8)
00012  *
00013  * Notes
00014  *      You can only change the defaults by recompiling the SystemVerilog code
00015  *      on the FPGA.
00016  */ 
00017  
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 FPGA_bus::FPGA_bus(int nos_PWM   /* = NOS_PWM_CHANNELS */, 
00021                    int nos_QE    /* = NOS_QE_CHANNELS  */, 
00022                    int nos_servo /* = NOS_RC_CHANNELS  */ )
00023                    
00024                 :   
00025                     _nos_PWM_units(nos_PWM),
00026                     _nos_QE_units(nos_QE),
00027                     _nos_servo_units(nos_servo),   
00028                                             
00029                     async_uP_start(ASYNC_UP_START_PIN), 
00030                     async_uP_handshake_1(ASYNC_UP_HANDSHAKE_1_PIN),
00031                     async_uP_RW(ASYNC_UP_RW_PIN),
00032                     async_uP_reset(ASYNC_UP_RESET_PIN),
00033                     uP_ack(ASYNC_UP_ACK_PIN),
00034                     uP_handshake_2(ASYNC_UP_HANDSHAKE_2_PIN),
00035                     log_pin(LOG_PIN)
00036                     
00037         {
00038         async_uP_start   = LOW;
00039         PWM_base         = 0;
00040         QE_base          = 0;
00041         RC_base          = 0;
00042 }
00043 
00044 //////////////////////////////////////////////////////////////////////////
00045 // do_reset : reset FPGA system
00046 // ========
00047 //
00048 // Generate a 20uS LOW going pulse to set FPGA into initial state
00049 
00050 void FPGA_bus:: do_reset(void)
00051 {
00052     async_uP_reset = LOW;       // generate low reset pulse
00053     wait_us(FPGA_RESET_PULSE_WIDTH);
00054     async_uP_reset = HIGH;
00055     wait_us(FPGA_RESET_PULSE_WIDTH);
00056 }
00057  
00058 //////////////////////////////////////////////////////////////////////////
00059 // initialise : Configure uP to FPGA data bus
00060 // ==========
00061 //
00062 // Do the following
00063 //  1. Set output signals to known values
00064 //  2. Prod FPGA to check that it is responding correctly
00065 //          Code  will make 3 attempts before returning with an ERROR    
00066 //  3. Read register ZERO to get number of units in FPGA
00067 //          This data is used to initialise the correct register pointers
00068 
00069 int32_t  FPGA_bus::initialise(void)
00070 {
00071 int32_t     status;
00072 
00073     status = NO_ERROR;
00074     
00075     // GPIOC Periph clock enable
00076     
00077     ENABLE_GPIO_SUBSYSTEM;
00078     wait_us(2);
00079     
00080     async_uP_start       = LOW;
00081     async_uP_reset       = HIGH;
00082     async_uP_handshake_1 = LOW;
00083     async_uP_RW          = LOW;
00084     
00085     do_reset();
00086 //
00087 // Test to see if FPGA is alive and well
00088 //    
00089     status = hard_check_bus();
00090     if (status != NO_ERROR) {
00091         global_FPGA_unit_error_flag = status;
00092         return status;
00093     }  
00094 //
00095 // Seems OK, now read register 0 and get basic system parameters
00096 //
00097     wait_us(1000);
00098     get_SYS_data();
00099     
00100     if (global_FPGA_unit_error_flag != NO_ERROR){
00101         return global_FPGA_unit_error_flag;
00102     }
00103     global_FPGA_unit_error_flag = NO_ERROR;
00104     log_pin = LOW;
00105     return NO_ERROR;
00106 }
00107 
00108 //////////////////////////////////////////////////////////////////////////  
00109 // do_start : generate signals to start of bus transaction 
00110 // ========
00111 
00112 void FPGA_bus::do_start(void)
00113 {
00114     async_uP_start       = HIGH;
00115     async_uP_handshake_1 = LOW;
00116     async_uP_start       = LOW;
00117 }
00118 
00119 //////////////////////////////////////////////////////////////////////////
00120 // do_end : do actions to complete bus transaction
00121 // ======
00122 
00123 void FPGA_bus::do_end(void)
00124 {
00125     while (uP_ack == HIGH)
00126         ;
00127     async_uP_start = LOW;
00128 }
00129 
00130 //////////////////////////////////////////////////////////////////////////
00131 // write_byte : write a byte of data to the FPGA
00132 // ==========
00133 
00134 void FPGA_bus::write_byte(uint32_t byte_value)
00135 {
00136     SET_BUS_OUTPUT;
00137     OUTPUT_BYTE_TO_BUS(byte_value);
00138     async_uP_RW = WRITE_BUS;
00139     async_uP_handshake_1 = HIGH;
00140     while (uP_handshake_2 == LOW)
00141         ;
00142     async_uP_handshake_1 = LOW;
00143     while (uP_handshake_2 == HIGH)
00144         ;
00145 }
00146 
00147 //////////////////////////////////////////////////////////////////////////
00148 // read_byte : read a byte of data from the FPGA
00149 // =========
00150 
00151 uint32_t FPGA_bus::read_byte(void)
00152 {
00153     SET_BUS_INPUT;
00154     async_uP_RW = READ_BUS;
00155     while (uP_handshake_2 == LOW)
00156         ;
00157     data = INPUT_BYTE_FROM_BUS;
00158     async_uP_handshake_1 = HIGH;
00159     while (uP_handshake_2 == HIGH)
00160         ;
00161     async_uP_handshake_1 = LOW;
00162     return data;
00163 }
00164 
00165 //////////////////////////////////////////////////////////////////////////
00166 // do write : write a SIX byte command to FPGA
00167 // ========
00168 
00169 void FPGA_bus::do_write(uint32_t command, 
00170               uint32_t register_address, 
00171               uint32_t register_data)
00172 {
00173     write_byte(command);
00174     write_byte(register_address);
00175     write_byte(register_data);
00176     write_byte(register_data>>8);
00177     write_byte(register_data>>16);
00178     write_byte(register_data>>24);
00179 }
00180 
00181 //////////////////////////////////////////////////////////////////////////
00182 // do_read : Read the results of FPGA command execution
00183 // =======
00184 
00185 void FPGA_bus::do_read(received_packet_t   *buffer)
00186 {
00187     for (int i=0; i < (NOS_RECEIVED_PACKET_WORDS<<2) ; i++) {
00188         buffer->byte_data[i] = (uint8_t)read_byte();
00189     }
00190 }
00191 
00192 //////////////////////////////////////////////////////////////////////////
00193 // do_transaction : execute complete command and get results
00194 // ==============
00195 
00196 void FPGA_bus::do_transaction(uint32_t command, 
00197                     uint32_t register_address, 
00198                     uint32_t register_data,
00199                     uint32_t *data,
00200                     uint32_t *status)
00201 {
00202     log_pin = HIGH;
00203     do_start();
00204     do_write(command, register_address, register_data);
00205     do_read(&in_pkt);
00206     do_end();
00207     log_pin = LOW;
00208     *data = in_pkt.word_data[0];
00209     *status = in_pkt.word_data[1];
00210 }
00211 
00212 ////////////////////////////////////////////////////////////////////////// 
00213 // set_PWM_period : set PWM period given frequency
00214 // ==============
00215    
00216 void FPGA_bus::set_PWM_period(uint32_t channel, float frequency)
00217 {
00218     uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_PERIOD);
00219     uint32_t period_value = (uint32_t)(1000000/(20 * frequency));
00220     do_transaction(WRITE_REGISTER_CMD, register_address, period_value, &data, &status); 
00221     sys_data.PWM_period_value[channel] = period_value;
00222     do_transaction(READ_REGISTER_CMD, (1 + (channel * NOS_PWM_REGISTERS)) , NULL, &data, &status);
00223     global_FPGA_unit_error_flag = status;
00224 }
00225 
00226 //////////////////////////////////////////////////////////////////////////
00227 // set_PWM_duty : set puty time at % of period
00228 // ============
00229 
00230 void FPGA_bus::set_PWM_duty(uint32_t channel, float percentage)
00231 {
00232     uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_ON_TIME);
00233     uint32_t duty_value = (uint32_t)((sys_data.PWM_period_value[channel] * percentage) / 100);
00234     do_transaction(WRITE_REGISTER_CMD, register_address , duty_value, &data, &status);
00235     sys_data.PWM_duty_value[channel] = duty_value;
00236     global_FPGA_unit_error_flag = status;;
00237 }
00238 
00239 //////////////////////////////////////////////////////////////////////////
00240 // PWM_enable : enable PWM output
00241 // ==========
00242 
00243 void FPGA_bus::PWM_enable(uint32_t channel)
00244 {
00245     uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG);
00246     do_transaction(WRITE_REGISTER_CMD, register_address , 1, &data, &status);
00247     global_FPGA_unit_error_flag = status;;
00248 }
00249 
00250 //////////////////////////////////////////////////////////////////////////
00251 // PWM_config : program PWM configuration register
00252 // ==========
00253 
00254 void FPGA_bus::PWM_config(uint32_t channel, uint32_t config_value)
00255 {
00256     uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG);
00257     do_transaction(WRITE_REGISTER_CMD, register_address , config_value, &data, &status);
00258     sys_data.PWM_duty_value[channel] = config_value;
00259     global_FPGA_unit_error_flag = status;;
00260 }
00261 
00262 //////////////////////////////////////////////////////////////////////////
00263 // set_RC_period : set RC period to 20mS for all servos
00264 // =============
00265 //
00266 // No parameter therefore assume 20mS period
00267 //
00268 // FPGA clock = 20nS => 20mS = 1,000,000 clocks counts
00269 
00270 void FPGA_bus::set_RC_period(void)
00271 {
00272     do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_PERIOD), 1000000, &data, &status);
00273     global_FPGA_unit_error_flag = status;
00274 }
00275 
00276 //////////////////////////////////////////////////////////////////////////
00277 // set_RC_period : set RC pulse in units of uS for all servos
00278 // =============
00279 //
00280 
00281 void FPGA_bus::set_RC_period(uint32_t duty_uS)
00282 {
00283     uint32_t nos_20nS_ticks = ((duty_uS * nS_IN_uS)/FPGA_CLOCK_PERIOD_nS);
00284     do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_PERIOD), nos_20nS_ticks, &data, &status);
00285     global_FPGA_unit_error_flag = status;
00286 }
00287 
00288 //////////////////////////////////////////////////////////////////////////
00289 // set_RC_pulse : set RC pulse width in uS for a particular servo
00290 // ============
00291 //
00292 
00293 void FPGA_bus :: set_RC_pulse(uint32_t channel, uint32_t pulse_uS)
00294 {
00295     uint32_t nos_20nS_ticks = ((pulse_uS * nS_IN_uS)/FPGA_CLOCK_PERIOD_nS);
00296     do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_ON_TIME + channel), nos_20nS_ticks, &data, &status);
00297     global_FPGA_unit_error_flag = status;;    
00298 }
00299 
00300 //////////////////////////////////////////////////////////////////////////
00301 // enable_RC_channel : enable RC servo channel output
00302 // =================
00303 
00304 void FPGA_bus::enable_RC_channel(uint32_t channel)
00305 {
00306     do_transaction(READ_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), NULL, &data, &status);
00307     int32_t config = (data || (0x01 << channel)) + GLOBAL_RC_ENABLE;
00308     do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), config, &data, &status);
00309     global_FPGA_unit_error_flag = status;
00310 }
00311 
00312 //////////////////////////////////////////////////////////////////////////
00313 // disable_RC_channel : disable RC servo channel output
00314 // ==================
00315 
00316 void FPGA_bus::disable_RC_channel(uint32_t channel)
00317 {
00318     do_transaction(READ_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), NULL, &data, &status);
00319     uint32_t config = data && ~(0x01 << channel);
00320     do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), config, &data, &status);
00321     global_FPGA_unit_error_flag = status;
00322 }
00323 
00324 //////////////////////////////////////////////////////////////////////////
00325 // QE_config : configure quadrature encoder unit
00326 // =========
00327 
00328 void FPGA_bus::QE_config(uint32_t channel, uint32_t config_value)
00329 {
00330     uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG);
00331     do_transaction(WRITE_REGISTER_CMD, register_address , config_value, &data, &status);
00332     global_FPGA_unit_error_flag = status;;
00333 }
00334 
00335 //////////////////////////////////////////////////////////////////////////
00336 // enable_speed_measure : enable speed calculation of encoder channel
00337 // ====================
00338 
00339 void FPGA_bus::enable_speed_measure(uint32_t channel, uint32_t config_value, uint32_t phase_time)
00340 {
00341     uint32_t register_base = (QE_base + (channel * NOS_QE_REGISTERS));
00342     do_transaction(WRITE_REGISTER_CMD, (register_base + QE_SIM_PHASE_TIME), phase_time, &data, &status);
00343     global_FPGA_unit_error_flag = status;
00344     if (status != NO_ERROR) {
00345         return;
00346     }
00347     do_transaction(WRITE_REGISTER_CMD, (register_base + QE_CONFIG), config_value, &data, &status);
00348     global_FPGA_unit_error_flag = status;
00349 }
00350 
00351 //////////////////////////////////////////////////////////////////////////
00352 // read_speed_measure : read current speed measurement
00353 // ==================
00354 
00355 uint32_t FPGA_bus::read_speed_measure(uint32_t channel)
00356 {
00357     uint32_t register_address = ((QE_base + (channel * NOS_QE_REGISTERS)) + QE_SPEED_BUFFER);
00358     do_transaction(READ_REGISTER_CMD, register_address, NULL, &data, &status);
00359     global_FPGA_unit_error_flag = status;
00360     return data;
00361 }
00362 
00363 //////////////////////////////////////////////////////////////////////////
00364 // read_count_measure : read encoder counter register
00365 // ==================
00366 
00367 uint32_t FPGA_bus::read_count_measure(uint32_t channel)
00368 {
00369     uint32_t register_address = ((QE_base + (channel * NOS_QE_REGISTERS)) + QE_COUNT_BUFFER);
00370     do_transaction(READ_REGISTER_CMD, register_address, NULL, &data, &status);
00371     global_FPGA_unit_error_flag = status;
00372     return data;
00373 }
00374 
00375 //////////////////////////////////////////////////////////////////////////
00376 // get_SYS_data : read system data from register 0
00377 // ============
00378 //
00379 // Notes
00380 //      Register data has information to define where the subsystem registers
00381 //      are located.  The software will therefore be independent of the 
00382 //      number of subsystems in the FPGA
00383 
00384 uint32_t FPGA_bus::get_SYS_data(void)
00385 {
00386     do_transaction(READ_REGISTER_CMD, SYS_DATA_REG_ADDR, NULL, &data, &status);
00387     sys_data.major_version          = (data & 0x0000000F);
00388     sys_data.minor_version          = (data >> 4)  & 0x0000000F;
00389     sys_data.number_of_PWM_channels = (data >> 8)  & 0x0000000F;
00390     sys_data.number_of_QE_channels  = (data >> 12) & 0x0000000F;
00391     sys_data.number_of_RC_channels  = (data >> 16) & 0x0000000F;
00392     
00393     update_FPGA_register_pointers();
00394     
00395     global_FPGA_unit_error_flag = status;
00396     return data;
00397 }
00398 //////////////////////////////////////////////////////////////////////////
00399 // update_FPGA_register_pointers : set pointer to FPGA register bank
00400 // =============================
00401 //
00402 // Accessing the units within the FPGA is by reading and writing to registers.
00403 // This block of registers is a contiguous block starting at ZERO, up to
00404 // a maximum of 255.  This implies that if the FPGA is configured with more
00405 // PWM units (say), then the addresses of the later units are changed.  
00406 //
00407 // To overcome this problem, register ZERO contains a note of the number of
00408 // PWM, QE, abd RC servo units.  This address is fixed and is read to 
00409 // calculate the relevant register address pointers.
00410 //
00411 
00412 void FPGA_bus::update_FPGA_register_pointers(void) {
00413     
00414     PWM_base = 1;
00415     QE_base  = ((NOS_PWM_REGISTERS * sys_data.number_of_PWM_channels) + PWM_base);
00416     RC_base  = ((NOS_QE_REGISTERS * sys_data.number_of_QE_channels) + QE_base);   
00417 }
00418 
00419 //////////////////////////////////////////////////////////////////////////
00420 // hard_check_bus : verify that connection to FPGA is working (uses RESET)
00421 // ==============
00422 //
00423 // Notes
00424 //      Timeout on a first handshake after a RESET. Uses first part of
00425 //      'write_byte' handshake to test bus
00426 // Return
00427 //      NO_ERROR   = bus active and replying correctly
00428 //      BUS_FAIL_1 = unable to get response from FPGA through bus
00429 //      BUS_FAIL_2 = unable to get response from FPGA through bus
00430 //
00431 int32_t FPGA_bus::hard_check_bus(void)
00432 {
00433     do_reset();
00434     wait_us(uS_DELAY_BEFORE_TEST_HANDSHAKE);
00435     
00436     if (uP_handshake_2 == HIGH) {
00437         return  BUS_FAIL_1;       // handshake line in wrong init state
00438     }
00439     
00440     do_start();
00441     SET_BUS_INPUT;
00442     async_uP_RW = READ_BUS;
00443     SET_BUS_OUTPUT;
00444     OUTPUT_BYTE_TO_BUS(0);
00445     async_uP_RW = WRITE_BUS;
00446     async_uP_handshake_1 = HIGH;
00447     wait_us(uS_DELAY_BEFORE_TEST_HANDSHAKE);
00448     
00449     if (uP_handshake_2 == LOW) {
00450         return BUS_FAIL_2;
00451     }  
00452 //
00453 // set system back to original state
00454 //
00455     async_uP_start       = LOW;
00456     async_uP_reset       = HIGH;
00457     async_uP_handshake_1 = LOW;
00458     async_uP_RW          = LOW;
00459     do_reset();
00460     return NO_ERROR;
00461 }
00462 
00463 //////////////////////////////////////////////////////////////////////////
00464 // soft_check_bus : verify that connection to FPGA is working (no RESET)
00465 // ==============
00466 //
00467 // Notes
00468 //      FPGA-uP bus FSM special cased to accept a handshake_2 signal BEFORE
00469 //      a START signal.  If handshake replies are not recieved in a timely
00470 //      manner, error codes are returned.
00471 // Return
00472 //      NO_ERROR   = bus active and replying correctly
00473 //      BUS_FAIL_1 = handshake line in wrong init state
00474 //      BUS_FAIL_2 = no handshake response
00475 //      BUS_FAIL_3 = handshake failed to terminate correctly
00476 //
00477 
00478 int32_t FPGA_bus::soft_check_bus(void)
00479 {
00480 uint32_t  timeout_counter;
00481 
00482     timeout_counter = HANDSHAKE_TIMEOUT_COUNT;
00483     while (uP_handshake_2 == HIGH) {
00484         timeout_counter--;
00485         if (timeout_counter == 0) {
00486             return  BUS_FAIL_1;       // handshake line in wrong init state
00487         }
00488     }
00489     async_uP_handshake_1 = HIGH;
00490     timeout_counter = HANDSHAKE_TIMEOUT_COUNT;
00491     while (uP_handshake_2 == LOW) {
00492         timeout_counter--;
00493         if (timeout_counter == 0) {
00494             async_uP_handshake_1 = LOW;
00495             return  BUS_FAIL_1;       // no handshake response
00496         }
00497     }
00498     async_uP_handshake_1 = LOW;
00499     timeout_counter = HANDSHAKE_TIMEOUT_COUNT;
00500     while (uP_handshake_2 == HIGH) {
00501         timeout_counter--;
00502         if (timeout_counter == 0) {
00503             return  BUS_FAIL_2;       // handshake failed to terminate correctly
00504         }
00505     }    
00506     return NO_ERROR;
00507 }
00508 
00509