Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Sun Jul 17 2022 12:02:03 by
