Comms between MAX 10 FPGA and ST uP

FPGA_bus.cpp

Committer:
jimherd
Date:
2019-04-18
Revision:
4:e5d36eee9245
Parent:
3:cf36c2d4208f
Child:
5:64c677e9995c

File content as of revision 4:e5d36eee9245:

/*
 * FPGA_bus : 8-bit bi-directional bus between uP and FPGA
 */
#include "mbed.h"
#include "FPGA_bus.h"

/** create a FPGA_bus object connecting uP to FPGA
 *
 * @param  nos_PWM      Number of PWM channels (default = 4)
 * @param  nos_QE       Number of Quadrature Encoder channels (default = 4)
 * @param  nos_servo    Number of RC servo channels (default = 8)
 *
 * Notes
 *      You can only change the defaults by recompiling the SystemVerilog code
 *      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)
                   
                :   async_uP_start(ASYNC_UP_START_PIN), 
                    async_uP_handshake_1(ASYNC_UP_HANDSHAKE_1_PIN),
                    async_uP_RW(ASYNC_UP_RW_PIN),
                    async_uP_reset(ASYNC_UP_RESET_PIN),
                    uP_ack(ASYNC_UP_ACK_PIN),
                    uP_handshake_2(ASYNC_UP_HANDSHAKE_2_PIN)                   
{
    _nos_PWM_units   = nos_PWM;
    _nos_QE_units    = nos_QE;
    _nos_servo_units = nos_servo;
    
    async_uP_start   = LOW;
}

FPGA_bus::FPGA_bus(void)
                :   async_uP_start(ASYNC_UP_START_PIN), 
                    async_uP_handshake_1(ASYNC_UP_HANDSHAKE_1_PIN),
                    async_uP_RW(ASYNC_UP_RW_PIN),
                    async_uP_reset(ASYNC_UP_RESET_PIN),
                    uP_ack(ASYNC_UP_ACK_PIN),
                    uP_handshake_2(ASYNC_UP_HANDSHAKE_2_PIN)                   
{
    _nos_PWM_units   = NOS_PWM_CHANNELS;
    _nos_QE_units    = NOS_QE_CHANNELS;
    _nos_servo_units = NOS_RC_CHANNELS;
    
    async_uP_start       = LOW;
}



void  FPGA_bus::initialise(void)
{
    // GPIOC Periph clock enable
    
    ENABLE_GPIO_SUBSYSTEM;
    wait_us(2);
    
    async_uP_start       = LOW;
    async_uP_reset       = HIGH;
    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);
    
    global_FPGA_unit_error_flag = NO_ERROR;
}
    
void FPGA_bus::do_start(void)
{
    async_uP_start       = HIGH;
    async_uP_handshake_1 = LOW;
    async_uP_start       = LOW;
}

void FPGA_bus::do_end(void)
{
    while (uP_ack == HIGH)
        ;
    async_uP_start = LOW;
}

void FPGA_bus::write_byte(uint32_t byte_value)
{
    SET_BUS_OUTPUT;
    OUTPUT_BYTE_TO_BUS(byte_value);
    async_uP_RW = WRITE_BUS;
    async_uP_handshake_1 = HIGH;
    while (uP_handshake_2 == LOW)
        ;
    async_uP_handshake_1 = LOW;
    while (uP_handshake_2 == HIGH)
        ;
}

uint32_t FPGA_bus::read_byte(void)
{
    SET_BUS_INPUT;
    async_uP_RW = READ_BUS;
    while (uP_handshake_2 == LOW)
        ;
    data = INPUT_BYTE_FROM_BUS;
    async_uP_handshake_1 = HIGH;
    while (uP_handshake_2 == HIGH)
        ;
    async_uP_handshake_1 = LOW;
    return data;
}

void FPGA_bus::do_write(uint32_t command, 
              uint32_t register_address, 
              uint32_t register_data)
{
    write_byte(command);
    write_byte(register_address);
    write_byte(register_data);
    write_byte(register_data>>8);
    write_byte(register_data>>16);
    write_byte(register_data>>24);
}

void FPGA_bus::do_read(received_packet_t   *buffer)
{
    for (int i=0; i < (NOS_RECEIVED_PACKET_WORDS<<2) ; i++) {
        buffer->byte_data[i] = (uint8_t)read_byte();
    }
}

void FPGA_bus::do_transaction(uint32_t command, 
                    uint32_t register_address, 
                    uint32_t register_data,
                    uint32_t *data,
                    uint32_t *status)
{
    do_start();
 //   pc.printf("\n1");
    do_write(command, register_address, register_data);
 //   pc.printf(" 2");
    do_read(&in_pkt);
 //   pc.printf(" 3");
    do_end();
 //   pc.printf(" 4\n");
    *data = in_pkt.word_data[0];
    *status = in_pkt.word_data[1];
   // pc.printf("data = %#08X  :: status = %#08X\n", in_pkt.word_data[0], in_pkt.word_data[1]);
}

uint32_t  FPGA_bus::do_command(FPGA_packet_t cmd_packet)
{
    async_uP_start = LOW;
    return 0;
}
    
void FPGA_bus::set_PWM_period(uint32_t channel, float frequency)
{
    uint32_t register_address = ((PWM_BASE + (channel * NOS_PWM_REGISTERS)) + PWM_PERIOD);
    uint32_t period_value = (uint32_t)(1000000/(20 * frequency));
    do_transaction(WRITE_REGISTER_CMD, register_address, period_value, &data, &status); 
    sys_data.PWM_period_value[channel] = period_value;
    global_FPGA_unit_error_flag = status;
}

void FPGA_bus::set_PWM_duty(uint32_t channel, float percentage)
{
    uint32_t register_address = ((PWM_BASE + (channel * NOS_PWM_REGISTERS)) + PWM_ON_TIME);
    uint32_t duty_value = (uint32_t)((sys_data.PWM_period_value[channel] * percentage) / 100);
    do_transaction(WRITE_REGISTER_CMD, register_address , duty_value, &data, &status);
    sys_data.PWM_duty_value[channel] = duty_value;
    global_FPGA_unit_error_flag = status;;
}

void FPGA_bus::PWM_enable(uint32_t channel)
{
    uint32_t register_address = ((PWM_BASE + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG);
    do_transaction(WRITE_REGISTER_CMD, register_address , 1, &data, &status);
 //   sys_data.PWM_duty_value[channel] = duty_value;
    global_FPGA_unit_error_flag = status;;
}

void FPGA_bus::PWM_config(uint32_t channel, uint32_t config_value)
{
    uint32_t register_address = ((PWM_BASE + (channel * NOS_PWM_REGISTERS)) + PWM_CONFIG);
    do_transaction(WRITE_REGISTER_CMD, register_address , config_value, &data, &status);
    sys_data.PWM_duty_value[channel] = config_value;
    global_FPGA_unit_error_flag = status;;
}

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;;
}

void FPGA_bus::set_RC_period(uint32_t duty_uS)
{
    uint32_t nos_20nS_ticks = ((duty_uS * nS_IN_uS)/FPGA_CLOCK_PERIOD_nS);
    do_transaction(WRITE_REGISTER_CMD, (RC_BASE + RC_SERVO_PERIOD), nos_20nS_ticks, &data, &status);
    global_FPGA_unit_error_flag = status;;
}

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);
    do_transaction(WRITE_REGISTER_CMD, (RC_BASE + RC_SERVO_ON_TIME + channel), nos_20nS_ticks, &data, &status);
    global_FPGA_unit_error_flag = status;;    
}

void FPGA_bus::enable_RC_channel(uint32_t channel)
{
    do_transaction(READ_REGISTER_CMD, (RC_BASE + RC_SERVO_CONFIG), NULL, &data, &status);
    int32_t config = (data || (0x01 << channel)) + GLOBAL_RC_ENABLE;
    do_transaction(WRITE_REGISTER_CMD, (RC_BASE + RC_SERVO_CONFIG), config, &data, &status);
    global_FPGA_unit_error_flag = status;
}

void FPGA_bus::disable_RC_channel(uint32_t channel)
{
    do_transaction(READ_REGISTER_CMD, (RC_BASE + RC_SERVO_CONFIG), NULL, &data, &status);
    uint32_t config = data && ~(0x01 << channel);
    do_transaction(WRITE_REGISTER_CMD, (RC_BASE + RC_SERVO_CONFIG), config, &data, &status);
    global_FPGA_unit_error_flag = status;
}

void FPGA_bus::enable_speed_measure(uint32_t channel)
{
    uint32_t register_address = ((QE_BASE + (channel * NOS_QE_REGISTERS)) + QE_CONFIG);
    uint32_t register_data = QE_SPEED_CALC_ENABLE;
    do_transaction(WRITE_REGISTER_CMD, register_address, register_data, &data, &status);
}