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.
Diff: FPGA_bus.cpp
- Revision:
- 20:aacf2ebd93ff
- Parent:
- 17:928b755cba80
- Child:
- 21:6b2b7a0e2d9a
diff -r bc9910b1c186 -r aacf2ebd93ff FPGA_bus.cpp --- a/FPGA_bus.cpp Mon May 25 14:14:17 2020 +0000 +++ b/FPGA_bus.cpp Mon Jun 15 21:29:40 2020 +0000 @@ -15,6 +15,8 @@ * on the FPGA. */ +////////////////////////////////////////////////////////////////////////// + FPGA_bus::FPGA_bus(int nos_PWM /* = NOS_PWM_CHANNELS */, int nos_QE /* = NOS_QE_CHANNELS */, int nos_servo /* = NOS_RC_CHANNELS */ ) @@ -39,11 +41,36 @@ RC_base = 0; } +////////////////////////////////////////////////////////////////////////// +// do_reset : reset FPGA system +// ======== +// +// Generate a 20uS LOW going pulse to set FPGA into initial state -void FPGA_bus::initialise(void) +void FPGA_bus:: do_reset(void) { + async_uP_reset = LOW; // generate low reset pulse + wait_us(20); + async_uP_reset = HIGH; + wait_us(20); +} + +////////////////////////////////////////////////////////////////////////// +// initialise : Configure uP to FPGA data bus +// ========== +// +// Do the following +// 1. Set output signals to known values +// 2. Prod FPGA to check that it is responding correctly +// Code will make 3 attempts before returning with an ERROR +// 3. Read register ZERO to get number of units in FPGA +// This data is used to initialise the correct register pointers - update_FPGA_register_pointers(); +int32_t FPGA_bus::initialise(void) +{ +int32_t status; + + status = NO_ERROR; // GPIOC Periph clock enable @@ -55,15 +82,33 @@ async_uP_handshake_1 = LOW; async_uP_RW = LOW; - async_uP_reset = LOW; // generate low reset pulse - wait_us(20); - async_uP_reset = HIGH; - wait_us(20); + do_reset(); +// +// Test to see if FPGA is alive and well +// + status = check_bus(); + if (status != NO_ERROR) { + global_FPGA_unit_error_flag = status; + return status; + } +// +// Seems OK, now read register 0 and get basic system parameters +// + wait_ms(10); + get_SYS_data(); + if (global_FPGA_unit_error_flag != NO_ERROR){ + return global_FPGA_unit_error_flag; + } global_FPGA_unit_error_flag = NO_ERROR; log_pin = LOW; + return NO_ERROR; } - + +////////////////////////////////////////////////////////////////////////// +// do_start : generate signals to start of bus transaction +// ======== + void FPGA_bus::do_start(void) { async_uP_start = HIGH; @@ -71,6 +116,10 @@ async_uP_start = LOW; } +////////////////////////////////////////////////////////////////////////// +// do_end : do actions to complete bus transaction +// ====== + void FPGA_bus::do_end(void) { while (uP_ack == HIGH) @@ -78,6 +127,10 @@ async_uP_start = LOW; } +////////////////////////////////////////////////////////////////////////// +// write_byte : write a byte of data to the FPGA +// ========== + void FPGA_bus::write_byte(uint32_t byte_value) { SET_BUS_OUTPUT; @@ -91,6 +144,10 @@ ; } +////////////////////////////////////////////////////////////////////////// +// read_byte : read a byte of data from the FPGA +// ========= + uint32_t FPGA_bus::read_byte(void) { SET_BUS_INPUT; @@ -105,6 +162,10 @@ return data; } +////////////////////////////////////////////////////////////////////////// +// do write : write a SIX byte command to FPGA +// ======== + void FPGA_bus::do_write(uint32_t command, uint32_t register_address, uint32_t register_data) @@ -117,6 +178,10 @@ write_byte(register_data>>24); } +////////////////////////////////////////////////////////////////////////// +// do_read : Read the results of FPGA command execution +// ======= + void FPGA_bus::do_read(received_packet_t *buffer) { for (int i=0; i < (NOS_RECEIVED_PACKET_WORDS<<2) ; i++) { @@ -124,6 +189,10 @@ } } +////////////////////////////////////////////////////////////////////////// +// do_transaction : execute complete command and get results +// ============== + void FPGA_bus::do_transaction(uint32_t command, uint32_t register_address, uint32_t register_data, @@ -140,12 +209,10 @@ *status = in_pkt.word_data[1]; } -uint32_t FPGA_bus::do_command(FPGA_packet_t cmd_packet) -{ - async_uP_start = LOW; - return 0; -} - +////////////////////////////////////////////////////////////////////////// +// set_PWM_period : set PWM period given frequency +// ============== + void FPGA_bus::set_PWM_period(uint32_t channel, float frequency) { uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_PERIOD); @@ -156,6 +223,10 @@ global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// set_PWM_duty : set puty time at % of period +// ============ + void FPGA_bus::set_PWM_duty(uint32_t channel, float percentage) { uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_ON_TIME); @@ -165,6 +236,10 @@ global_FPGA_unit_error_flag = status;; } +////////////////////////////////////////////////////////////////////////// +// PWM_enable : enable PWM output +// ========== + void FPGA_bus::PWM_enable(uint32_t channel) { uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG); @@ -172,6 +247,10 @@ global_FPGA_unit_error_flag = status;; } +////////////////////////////////////////////////////////////////////////// +// PWM_config : program PWM configuration register +// ========== + void FPGA_bus::PWM_config(uint32_t channel, uint32_t config_value) { uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG); @@ -180,12 +259,25 @@ global_FPGA_unit_error_flag = status;; } +////////////////////////////////////////////////////////////////////////// +// set_RC_period : set RC period to 20mS for all servos +// ============= +// +// No parameter therefore assume 20mS period +// +// FPGA clock = 20nS => 20mS = 1,000,000 clocks counts + void FPGA_bus::set_RC_period(void) { do_transaction(WRITE_REGISTER_CMD, (RC_base + RC_SERVO_PERIOD), 1000000, &data, &status); global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// set_RC_period : set RC pulse in units of uS for all servos +// ============= +// + void FPGA_bus::set_RC_period(uint32_t duty_uS) { uint32_t nos_20nS_ticks = ((duty_uS * nS_IN_uS)/FPGA_CLOCK_PERIOD_nS); @@ -193,6 +285,11 @@ global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// set_RC_pulse : set RC pulse width in uS for a particular servo +// ============ +// + void FPGA_bus :: set_RC_pulse(uint32_t channel, uint32_t pulse_uS) { uint32_t nos_20nS_ticks = ((pulse_uS * nS_IN_uS)/FPGA_CLOCK_PERIOD_nS); @@ -200,6 +297,10 @@ global_FPGA_unit_error_flag = status;; } +////////////////////////////////////////////////////////////////////////// +// enable_RC_channel : enable RC servo channel output +// ================= + void FPGA_bus::enable_RC_channel(uint32_t channel) { do_transaction(READ_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), NULL, &data, &status); @@ -208,6 +309,10 @@ global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// disable_RC_channel : disable RC servo channel output +// ================== + void FPGA_bus::disable_RC_channel(uint32_t channel) { do_transaction(READ_REGISTER_CMD, (RC_base + RC_SERVO_CONFIG), NULL, &data, &status); @@ -216,6 +321,10 @@ global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// QE_config : configure quadrature encoder unit +// ========= + void FPGA_bus::QE_config(uint32_t channel, uint32_t config_value) { uint32_t register_address = ((PWM_base + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG); @@ -223,6 +332,10 @@ global_FPGA_unit_error_flag = status;; } +////////////////////////////////////////////////////////////////////////// +// enable_speed_measure : enable speed calculation of encoder channel +// ==================== + void FPGA_bus::enable_speed_measure(uint32_t channel, uint32_t config_value, uint32_t phase_time) { uint32_t register_base = (QE_base + (channel * NOS_QE_REGISTERS)); @@ -235,6 +348,10 @@ global_FPGA_unit_error_flag = status; } +////////////////////////////////////////////////////////////////////////// +// read_speed_measure : read current speed measurement +// ================== + uint32_t FPGA_bus::read_speed_measure(uint32_t channel) { uint32_t register_address = ((QE_base + (channel * NOS_QE_REGISTERS)) + QE_SPEED_BUFFER); @@ -243,6 +360,10 @@ return data; } +////////////////////////////////////////////////////////////////////////// +// read_count_measure : read encoder counter register +// ================== + uint32_t FPGA_bus::read_count_measure(uint32_t channel) { uint32_t register_address = ((QE_base + (channel * NOS_QE_REGISTERS)) + QE_COUNT_BUFFER); @@ -251,22 +372,100 @@ return data; } +////////////////////////////////////////////////////////////////////////// +// get_SYS_data : read system data from register 0 +// ============ +// +// Notes +// Register data has information to define where the subsystem registers +// are located. The software will therefore be independent of the +// number of subsystems in the FPGA + uint32_t FPGA_bus::get_SYS_data(void) { do_transaction(READ_REGISTER_CMD, SYS_DATA_REG_ADDR, NULL, &data, &status); sys_data.major_version = (data & 0x0000000F); - sys_data.minor_version = (data >> 4) & 0x0000000F; - sys_data.number_of_PWM_channels = (data >> 8) & 0x0000000F; - sys_data.number_of_QE_channels = (data >> 8) & 0x0000000F; - sys_data.number_of_RC_channels = (data >> 8) & 0x0000000F; + sys_data.minor_version = (data >> 4) & 0x0000000F; + sys_data.number_of_PWM_channels = (data >> 8) & 0x0000000F; + sys_data.number_of_QE_channels = (data >> 12) & 0x0000000F; + sys_data.number_of_RC_channels = (data >> 16) & 0x0000000F; + + update_FPGA_register_pointers(); global_FPGA_unit_error_flag = status; return data; } +////////////////////////////////////////////////////////////////////////// +// update_FPGA_register_pointers : set pointer to FPGA register bank +// ============================= +// +// Accessing the units within the FPGA is by reading and writing to registers. +// This block of registers is a contiguous block starting at ZERO, up to +// a maximum of 255. This implies that if the FPGA is configured with more +// PWM units (say), then the addresses of the later units are changed. +// +// To overcome this problem, register ZERO contains a note of the number of +// PWM, QE, abd RC servo units. This address is fixed and is read to +// calculate the relevant register address pointers. +// void FPGA_bus::update_FPGA_register_pointers(void) { PWM_base = 1; - QE_base = ((NOS_PWM_REGISTERS * _nos_PWM_units) + PWM_base); - RC_base = ((NOS_QE_REGISTERS * _nos_QE_units) + QE_base); -} \ No newline at end of file + QE_base = ((NOS_PWM_REGISTERS * sys_data.number_of_PWM_channels) + PWM_base); + RC_base = ((NOS_QE_REGISTERS * sys_data.number_of_QE_channels) + QE_base); +} + +////////////////////////////////////////////////////////////////////////// +// check_bus : verify that connection to FPGA is working +// ========= +// +// Notes +// Timeout on a first handshake after a RESET. Uses first part of +// 'write_byte' handshake to test bus +// Three attempts are made before a fault is returned. +// Return +// OK = bus active and replying correctly +// BUS_FAIL = unable to get response from FPGA through bus +// +int32_t FPGA_bus::check_bus(void) +{ + + int32_t status = NO_ERROR; + for (uint32_t i=0 ; i < NOS_BUS_CHECKS ; i++) { + do_reset(); + do_start(); + SET_BUS_INPUT; + async_uP_RW = READ_BUS; + + SET_BUS_OUTPUT; + OUTPUT_BYTE_TO_BUS(0); + async_uP_RW = WRITE_BUS; + async_uP_handshake_1 = HIGH; + + + uint32_t timeout_count = BUS_TEST_TIMEOUT; + + while (uP_handshake_2 == LOW) { + timeout_count--; + if (timeout_count == 0) { + status = BUS_FAIL; + continue; // try again + } + } + + status = NO_ERROR; + break; + } +// +// set system back to original state +// + async_uP_start = LOW; + async_uP_reset = HIGH; + async_uP_handshake_1 = LOW; + async_uP_RW = LOW; + do_reset(); + return status; +} + + \ No newline at end of file