mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #10540 from c1728p9/fpga_ci_test_shield
Check in files for the FPGA CI Test Shieldpull/10663/head
commit
a4738fa9a8
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "DynamicPinList.h"
|
||||
|
||||
DynamicPinList::DynamicPinList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DynamicPinList::DynamicPinList(const PinList *pin_list)
|
||||
{
|
||||
for (uint32_t i = 0; i < pin_list->count; i++) {
|
||||
_pins.push_back(pin_list->pins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
DynamicPinList::DynamicPinList(const DynamicPinList &other)
|
||||
{
|
||||
_pins = other._pins;
|
||||
}
|
||||
|
||||
void DynamicPinList::add(PinName pin)
|
||||
{
|
||||
_pins.push_back(pin);
|
||||
}
|
||||
|
||||
bool DynamicPinList::has_pin(PinName pin) const
|
||||
{
|
||||
for (uint32_t i = 0; i < _pins.size(); i++) {
|
||||
if (pin == _pins[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DynamicPinList::clear()
|
||||
{
|
||||
_pins.clear();
|
||||
}
|
||||
|
||||
uint32_t DynamicPinList::count() const
|
||||
{
|
||||
return _pins.size();
|
||||
}
|
||||
|
||||
PinName DynamicPinList::get(uint32_t index) const
|
||||
{
|
||||
return index < _pins.size() ? _pins[index] : NC;
|
||||
}
|
||||
|
||||
int DynamicPinList::index(PinName pin) const
|
||||
{
|
||||
for (uint32_t i = 0; i < _pins.size(); i++) {
|
||||
if (pin == _pins[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DYNAMIC_PIN_LIST_H
|
||||
#define DYNAMIC_PIN_LIST_H
|
||||
|
||||
#include "pinmap.h"
|
||||
#include <vector>
|
||||
|
||||
class DynamicPinList {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create an empty pin list
|
||||
*/
|
||||
DynamicPinList();
|
||||
|
||||
/**
|
||||
* Create a pin list with the given contents
|
||||
*
|
||||
* @param pin_list List of pins to create this list from
|
||||
*/
|
||||
DynamicPinList(const PinList *pin_list);
|
||||
|
||||
/**
|
||||
* Create a copy of another list
|
||||
*
|
||||
* @param other Other object to copy contruct this from
|
||||
*/
|
||||
DynamicPinList(const DynamicPinList &other);
|
||||
|
||||
/**
|
||||
* Add a pin to the pin list
|
||||
*
|
||||
* @param pin Pin to add to this pin list
|
||||
*/
|
||||
void add(PinName pin);
|
||||
|
||||
/**
|
||||
* Check if the given pin is in this list
|
||||
*
|
||||
* @param pin Pin to check for in the list
|
||||
* @return true if the pin is in the list, false otherwise
|
||||
*/
|
||||
bool has_pin(PinName pin) const;
|
||||
|
||||
/**
|
||||
* Empty this pin list
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Return the number of pins in this list
|
||||
*
|
||||
* @return Elements in this list
|
||||
*/
|
||||
uint32_t count() const;
|
||||
|
||||
/**
|
||||
* Get the pin at the given index
|
||||
*
|
||||
* @return Pin at this position
|
||||
*/
|
||||
PinName get(uint32_t index) const;
|
||||
|
||||
/**
|
||||
* Get the location of the given pin
|
||||
*
|
||||
* @param pin Pin to get the index of
|
||||
* @return pin index or -1 if pin is not in the list
|
||||
*/
|
||||
int index(PinName pin) const;
|
||||
|
||||
private:
|
||||
std::vector<PinName> _pins;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "I2CTester.h"
|
||||
#include "fpga_config.h"
|
||||
|
||||
uint8_t I2CTester::num_starts()
|
||||
{
|
||||
uint8_t num_starts = 0;
|
||||
read(TESTER_I2C_STARTS, &num_starts, sizeof(num_starts));
|
||||
return num_starts;
|
||||
}
|
||||
|
||||
uint8_t I2CTester::num_stops()
|
||||
{
|
||||
uint8_t num_stops = 0;
|
||||
read(TESTER_I2C_STOPS, &num_stops, sizeof(num_stops));
|
||||
return num_stops;
|
||||
}
|
||||
|
||||
uint16_t I2CTester::num_acks()
|
||||
{
|
||||
uint16_t num_acks = 0;
|
||||
read(TESTER_I2C_ACKS, (uint8_t *)&num_acks, sizeof(num_acks));
|
||||
return num_acks;
|
||||
}
|
||||
|
||||
uint16_t I2CTester::num_nacks()
|
||||
{
|
||||
uint16_t num_nacks = 0;
|
||||
read(TESTER_I2C_NACKS, (uint8_t *)&num_nacks, sizeof(num_nacks));
|
||||
return num_nacks;
|
||||
}
|
||||
|
||||
uint16_t I2CTester::transfer_count()
|
||||
{
|
||||
uint16_t transfers = 0;
|
||||
MBED_ASSERT(sizeof(transfers) == TESTER_I2C_TRANSFERS_SIZE);
|
||||
read(TESTER_I2C_TRANSFERS, (uint8_t *)&transfers, sizeof(transfers));
|
||||
return transfers;
|
||||
}
|
||||
|
||||
uint32_t I2CTester::get_receive_checksum()
|
||||
{
|
||||
uint32_t to_slave_checksum = 0;
|
||||
MBED_ASSERT(sizeof(to_slave_checksum) == TESTER_I2C_TO_SLAVE_CHECKSUM_SIZE);
|
||||
read(TESTER_I2C_TO_SLAVE_CHECKSUM, (uint8_t *)&to_slave_checksum, sizeof(to_slave_checksum));
|
||||
return to_slave_checksum;
|
||||
}
|
||||
|
||||
uint8_t I2CTester::state_num()
|
||||
{
|
||||
uint8_t state_num = 0;
|
||||
read(TESTER_I2C_STATE_NUM, &state_num, sizeof(state_num));
|
||||
return state_num;
|
||||
}
|
||||
|
||||
uint8_t I2CTester::num_dev_addr_matches()
|
||||
{
|
||||
uint8_t num_correct = 0;
|
||||
read(TESTER_I2C_NUMBER_DEV_ADDR_MATCHES, &num_correct, sizeof(num_correct));
|
||||
return num_correct;
|
||||
}
|
||||
|
||||
void I2CTester::set_device_address(uint16_t addr)
|
||||
{
|
||||
uint16_t data = addr;
|
||||
write(TESTER_I2C_DEVICE_ADDRESS, (uint8_t *)&data, sizeof(data));
|
||||
}
|
||||
|
||||
uint16_t I2CTester::get_device_address()
|
||||
{
|
||||
uint16_t addr = 0;
|
||||
read(TESTER_I2C_DEVICE_ADDRESS, (uint8_t *)&addr, sizeof(addr));
|
||||
return addr;
|
||||
}
|
||||
|
||||
void I2CTester::set_sda(uint8_t value)
|
||||
{
|
||||
uint8_t val = value;
|
||||
write(TESTER_I2C_SET_SDA, &val, sizeof(val));
|
||||
}
|
||||
|
||||
uint8_t I2CTester::get_prev_to_slave_4()
|
||||
{
|
||||
uint8_t prev_to_slave_4 = 0;
|
||||
read(TESTER_I2C_PREV_TO_SLAVE_4, &prev_to_slave_4, sizeof(prev_to_slave_4));
|
||||
return prev_to_slave_4;
|
||||
}
|
||||
uint8_t I2CTester::get_prev_to_slave_3()
|
||||
{
|
||||
uint8_t prev_to_slave_3 = 0;
|
||||
read(TESTER_I2C_PREV_TO_SLAVE_3, &prev_to_slave_3, sizeof(prev_to_slave_3));
|
||||
return prev_to_slave_3;
|
||||
}
|
||||
uint8_t I2CTester::get_prev_to_slave_2()
|
||||
{
|
||||
uint8_t prev_to_slave_2 = 0;
|
||||
read(TESTER_I2C_PREV_TO_SLAVE_2, &prev_to_slave_2, sizeof(prev_to_slave_2));
|
||||
return prev_to_slave_2;
|
||||
}
|
||||
uint8_t I2CTester::get_prev_to_slave_1()
|
||||
{
|
||||
uint8_t prev_to_slave_1 = 0;
|
||||
read(TESTER_I2C_PREV_TO_SLAVE_1, &prev_to_slave_1, sizeof(prev_to_slave_1));
|
||||
return prev_to_slave_1;
|
||||
}
|
||||
void I2CTester::set_next_from_slave(uint8_t value)
|
||||
{
|
||||
uint8_t val = value;
|
||||
write(TESTER_I2C_NEXT_FROM_SLAVE, &val, sizeof(val));
|
||||
}
|
||||
uint8_t I2CTester::get_next_from_slave()
|
||||
{
|
||||
uint8_t next_from_slave = 0;
|
||||
read(TESTER_I2C_NEXT_FROM_SLAVE, &next_from_slave, sizeof(next_from_slave));
|
||||
return next_from_slave;
|
||||
}
|
||||
uint16_t I2CTester::num_writes()
|
||||
{
|
||||
uint16_t num_writes = 0;
|
||||
read(TESTER_I2C_NUM_WRITES, (uint8_t *)&num_writes, sizeof(num_writes));
|
||||
return num_writes;
|
||||
}
|
||||
uint16_t I2CTester::num_reads()
|
||||
{
|
||||
uint16_t num_reads = 0;
|
||||
read(TESTER_I2C_NUM_READS, (uint8_t *)&num_reads, sizeof(num_reads));
|
||||
return num_reads;
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef I2C_TESTER_H
|
||||
#define I2C_TESTER_H
|
||||
|
||||
#include "MbedTester.h"
|
||||
|
||||
|
||||
class I2CTester: public MbedTester {
|
||||
public:
|
||||
|
||||
I2CTester(const PinList *form_factor, const PinList *exclude_pins)
|
||||
: MbedTester(form_factor, exclude_pins)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* **I2C peripheral functions** */
|
||||
|
||||
/**
|
||||
* Get the number of start conditions since last I2C reset
|
||||
*
|
||||
* @return The number of start conditions
|
||||
*/
|
||||
uint8_t num_starts();
|
||||
|
||||
/**
|
||||
* Get the number of stop conditions since last I2C reset
|
||||
*
|
||||
* @return The number of stop conditions
|
||||
*/
|
||||
uint8_t num_stops();
|
||||
|
||||
/**
|
||||
* Get the number of ACKs since last I2C reset
|
||||
*
|
||||
* @return The number of ACKs
|
||||
*/
|
||||
uint16_t num_acks();
|
||||
|
||||
/**
|
||||
* Get the number of NACKs since last I2C reset
|
||||
*
|
||||
* @return The number of NACKs
|
||||
*/
|
||||
uint16_t num_nacks();
|
||||
|
||||
/**
|
||||
* Read the number of transfers which have occurred, not including the device address byte
|
||||
*
|
||||
* @return The number of I2C transfers that have completed since
|
||||
* i2c was reset, not including the device address byte
|
||||
*/
|
||||
uint16_t transfer_count();
|
||||
|
||||
/**
|
||||
* Read a checksum of data send to the tester
|
||||
*
|
||||
* @return The sum of all bytes sent to the tester since reset
|
||||
*/
|
||||
uint32_t get_receive_checksum();
|
||||
|
||||
/**
|
||||
* Get the I2C slave state number
|
||||
*
|
||||
* @return The state number
|
||||
*/
|
||||
uint8_t state_num();
|
||||
|
||||
/**
|
||||
* Get the number of times the device address has been sent correctly
|
||||
*
|
||||
* @return The number of times the device address has been sent correctly
|
||||
*/
|
||||
uint8_t num_dev_addr_matches();
|
||||
|
||||
/**
|
||||
* Set the I2C slave device address
|
||||
*
|
||||
* @param addr New address for slave device
|
||||
*/
|
||||
void set_device_address(uint16_t addr);
|
||||
|
||||
/**
|
||||
* Get the I2C slave device address
|
||||
*
|
||||
* @return The slave device address
|
||||
*/
|
||||
uint16_t get_device_address();
|
||||
|
||||
/**
|
||||
* Set SDA (test mode)
|
||||
*
|
||||
* @param value Test value for SDA
|
||||
*/
|
||||
void set_sda(uint8_t value);
|
||||
|
||||
/**
|
||||
* Get the value written to slave in the fourth to last transaction
|
||||
*
|
||||
* @return value written to slave in the fourth to last transaction
|
||||
*/
|
||||
uint8_t get_prev_to_slave_4();
|
||||
|
||||
/**
|
||||
* Get the value written to slave in the third to last transaction
|
||||
*
|
||||
* @return value written to slave in the third to last transaction
|
||||
*/
|
||||
uint8_t get_prev_to_slave_3();
|
||||
|
||||
/**
|
||||
* Get the value written to slave in the second to last transaction
|
||||
*
|
||||
* @return value written to slave in the second to last transaction
|
||||
*/
|
||||
uint8_t get_prev_to_slave_2();
|
||||
|
||||
/**
|
||||
* Get the value written to slave in the last transaction
|
||||
*
|
||||
* @return value written to slave in the last transaction
|
||||
*/
|
||||
uint8_t get_prev_to_slave_1();
|
||||
|
||||
/**
|
||||
* Set the value to be read from slave in next read transaction
|
||||
*
|
||||
* @param value Value to be read from slave in next read transaction
|
||||
*/
|
||||
void set_next_from_slave(uint8_t value);
|
||||
|
||||
/**
|
||||
* Get the value to be read from slave in next read transaction
|
||||
*
|
||||
* @return Value to be read from slave in next read transaction
|
||||
*/
|
||||
uint8_t get_next_from_slave();
|
||||
|
||||
/**
|
||||
* Read the number of writes which have occurred, not including the device address byte
|
||||
*
|
||||
* @return The number of I2C writes that have completed since
|
||||
* i2c was reset, not including the device address byte
|
||||
*/
|
||||
uint16_t num_writes();
|
||||
|
||||
/**
|
||||
* Read the number of reads which have occurred
|
||||
*
|
||||
* @return The number of I2C reads that have completed since
|
||||
* i2c was reset
|
||||
*/
|
||||
uint16_t num_reads();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,922 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MBED_TESTER_H
|
||||
#define MBED_TESTER_H
|
||||
|
||||
#include "DynamicPinList.h"
|
||||
#include "platform/FileHandle.h"
|
||||
#include "platform/Callback.h"
|
||||
#include "drivers/DigitalInOut.h"
|
||||
|
||||
/**
|
||||
* The base class for controlling the FPGA CI Test Shield
|
||||
*
|
||||
* This is the primary interface to the FPGA CI Test Shield. It contains
|
||||
* all the code to communicate with the FPGA. It also provides high level
|
||||
* helper functions, such as functions to setup pin multiplexing, to
|
||||
* select the currently active peripheral and to perform software updates.
|
||||
*
|
||||
* Subclasses can inherit from this class and provide further functionality,
|
||||
* such as the ability to test SPI.
|
||||
*
|
||||
* @note Synchronization level: Not protected
|
||||
*
|
||||
* Example of how to toggle Arduino pin D6 from the FPGA cI Test Shield:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
* #include "MbedTester.h"
|
||||
*
|
||||
* const PinList *form_factor = pinmap_ff_default_pins();
|
||||
* const PinList *restricted = pinmap_restricted_pins();
|
||||
* MbedTester tester(form_factor, restricted);
|
||||
*
|
||||
* int main() {
|
||||
* // Reset the FPGA CI Test Shield to put it into a known state
|
||||
* tester.reset();
|
||||
*
|
||||
* // Select the GPIO peripheral
|
||||
* tester.select_peripheral(MbedTester::PeripheralGPIO);
|
||||
*
|
||||
* // Map D6 to LogicalPinGPIO0
|
||||
* tester.pin_map_set(D6, MbedTester::LogicalPinGPIO0);
|
||||
*
|
||||
* // Toggle the LED
|
||||
* int toggle = 0;
|
||||
* while (1) {
|
||||
* tester.gpio_write(MbedTester::LogicalPinGPIO0, toggle, true);
|
||||
* wait(0.5);
|
||||
* toggle = !toggle;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class MbedTester {
|
||||
public:
|
||||
|
||||
/*
|
||||
* This type represents the index of a physical pin on the FPGA.
|
||||
* This can be any value from 0 to 127. A form factor is used to
|
||||
* map a PinName to a physical pin index.
|
||||
*/
|
||||
typedef uint8_t PhysicalIndex;
|
||||
|
||||
/*
|
||||
* There are 8 logical pins connected to the peripherals inside the FPGA.
|
||||
* These are logical pins 0 through 7. All peripherals can read from these
|
||||
* pins and the currently active peripheral can output on these pins.
|
||||
*
|
||||
* Each logical pin has a fixed function for a given peripheral which is
|
||||
* why the same value is defined multiple times. For example logical pin
|
||||
* 2 is SPI clock (SPISclk) when SPI is the active peripheral and
|
||||
* UART clear to send (UARTCts) when UART is the active peripheral.
|
||||
*
|
||||
* A logic pin can be mapped to any physical pin (PinName type) by calling
|
||||
* the function MbedTester::pin_map_set.
|
||||
*/
|
||||
enum LogicalPin {
|
||||
|
||||
LogicalPinGPIO0 = 0,
|
||||
LogicalPinGPIO1 = 1,
|
||||
LogicalPinGPIO2 = 2,
|
||||
LogicalPinGPIO3 = 3,
|
||||
LogicalPinGPIO4 = 4,
|
||||
LogicalPinGPIO5 = 5,
|
||||
LogicalPinGPIO6 = 6,
|
||||
LogicalPinGPIO7 = 7,
|
||||
|
||||
LogicalPinSPIMosi = 0,
|
||||
LogicalPinSPIMiso = 1,
|
||||
LogicalPinSPISclk = 2,
|
||||
LogicalPinSPISsel = 3,
|
||||
|
||||
LogicalPinIOMetrics0 = 0,
|
||||
LogicalPinIOMetrics1 = 1,
|
||||
LogicalPinIOMetrics2 = 2,
|
||||
LogicalPinIOMetrics3 = 3,
|
||||
LogicalPinIOMetrics4 = 4,
|
||||
LogicalPinIOMetrics5 = 5,
|
||||
LogicalPinIOMetrics6 = 6,
|
||||
LogicalPinIOMetrics7 = 7,
|
||||
|
||||
LogicalPinUARTTx = 0,
|
||||
LogicalPinUARTRx = 1,
|
||||
LogicalPinUARTCts = 2,
|
||||
LogicalPinUARTRts = 3,
|
||||
|
||||
LogicalPinI2CSda = 0,
|
||||
LogicalPinI2CScl = 1,
|
||||
|
||||
LogicalPinCount = 8,
|
||||
LogicalPinBanks = 2,
|
||||
LogicalPinTotal = LogicalPinCount * LogicalPinBanks
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the peripherals internal to the FPGA. A peripheral can be
|
||||
* selected by calling MbedTester::select_peripheral.
|
||||
*/
|
||||
enum Peripheral {
|
||||
PeripheralGPIO = 1,
|
||||
PeripheralSPI = 2,
|
||||
PeripheralUART = 4,
|
||||
PeripheralI2C = 5,
|
||||
PeripheralSPISlave = 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a new MbedTester object
|
||||
*
|
||||
* The form factor pins passed into this class must match the
|
||||
* physical MbedTester shield connected to this board or testing
|
||||
* will not work correctly. The order of pins in this list must
|
||||
* match the order of the shield.
|
||||
*
|
||||
* The exclude pins list should be used to exclude pins which you either
|
||||
* don't want to be tested or are not suitable for use as a control
|
||||
* channel. This list is allowed to contain pins that are not in the
|
||||
* form factor.
|
||||
*
|
||||
* @param form_factor The pins that are available on this form factor
|
||||
* @param exclude_pins The pins that must not be used
|
||||
*/
|
||||
MbedTester(const PinList *form_factor, const PinList *exclude_pins);
|
||||
|
||||
/**
|
||||
* Destroy and cleanup resources associated with this object
|
||||
*/
|
||||
~MbedTester();
|
||||
|
||||
/**
|
||||
* Enable automatic selection and update of control pins
|
||||
*
|
||||
* Calling this function configures MbedTester to automatically select
|
||||
* and update the control pins. The control pins are moved if the
|
||||
* function MbedTester::pin_map_set is called and maps a pin that is being used
|
||||
* for control.
|
||||
*
|
||||
* @note Automatic selection and update of control pins is the default.
|
||||
* Unless MbedTester::set_control_pins_manual has been called to manually
|
||||
* set the control pins this function has no effect.
|
||||
*/
|
||||
void set_control_pins_auto();
|
||||
|
||||
/**
|
||||
* Set the control pins to use for communication
|
||||
*
|
||||
* Manually set the control pins. Calling this function
|
||||
* disables automatic control pin selection and updates.
|
||||
* The function MbedTester::pin_map_set must not be used to map over
|
||||
* control pins when in this mode.
|
||||
*
|
||||
* @param clk Clock pin to use as the control channel
|
||||
* @param mosi Mosi pin to use as the control channel
|
||||
* @param miso Miso pin to use as the control channel
|
||||
* @param aux Auxillary pin to use as the control cannel
|
||||
*/
|
||||
void set_control_pins_manual(PinName clk, PinName mosi, PinName miso, PinName aux);
|
||||
|
||||
/**
|
||||
* Read FPGA CI Test Shield firmware
|
||||
*
|
||||
* Read the firmware on the FPGA CI Test Shield. An optional progress callback
|
||||
* can be supplied to display progress while the firmware is being read.
|
||||
*
|
||||
* @param dest File to write the firmware to. This file must have been opened as writeable
|
||||
* @param progress Optional progress callback called when the percent complete changes
|
||||
* @return true if firmware was successfully read, false otherwise
|
||||
*/
|
||||
bool firmware_dump(mbed::FileHandle *dest, mbed::Callback<void(uint8_t)> progress = mbed::Callback<void(uint8_t)>());
|
||||
|
||||
/**
|
||||
* Read FPGA CI Test Shield flash
|
||||
*
|
||||
* Read the entire flash contents of the FPGA CI Test Shield. An optional progress callback
|
||||
* can be supplied to display progress while the firmware is being read.
|
||||
*
|
||||
* @param dest File to write the firmware to. This file must have been opened as writeable
|
||||
* @param progress Optional progress callback called when the percent complete changes
|
||||
* @return true if firmware was successfully read, false otherwise
|
||||
*/
|
||||
bool firmware_dump_all(mbed::FileHandle *dest, mbed::Callback<void(uint8_t)> progress = mbed::Callback<void(uint8_t)>());
|
||||
|
||||
/**
|
||||
* Program new FPGA CI Test Shield firmware
|
||||
*
|
||||
* Program firmware from the file given. The binary bitstream must be in the correct format
|
||||
* and contain a correct CRC or the update will fail. To correctly format a bitstream binary
|
||||
* the post_process_bitstream.py script in the fpga-ci-test-shield repository should be used.
|
||||
*
|
||||
* Note - release binaries for the FPGA CI Test Shield have already been formatted and
|
||||
* can be loaded directly with this function
|
||||
*
|
||||
* @param src File containing the new firmware to program
|
||||
* @param progress Optional progress callback called when the percent complete changes
|
||||
* @return true if firmware was successfully applied, false otherwise
|
||||
*/
|
||||
bool firmware_update(mbed::FileHandle *src, mbed::Callback<void(uint8_t)> progress = mbed::Callback<void(uint8_t)>());
|
||||
|
||||
/**
|
||||
* Map a physical pin to the given logical pin
|
||||
*
|
||||
* This function will automatically move the control channel
|
||||
* pins to avoid interfering with the mapped pin.
|
||||
*
|
||||
* @param physical Physical pin on the board
|
||||
* @param logical Logical pin to map to
|
||||
*/
|
||||
void pin_map_set(PinName physical, LogicalPin logical);
|
||||
|
||||
/**
|
||||
* Reset all pin mappings
|
||||
*
|
||||
* After this call all pins will be unmapped
|
||||
*/
|
||||
void pin_map_reset();
|
||||
|
||||
/**
|
||||
* Reset all peripherals
|
||||
*
|
||||
* This does not reset the pin mappings
|
||||
*/
|
||||
void peripherals_reset();
|
||||
|
||||
/**
|
||||
* Reset everything
|
||||
*
|
||||
* This function resets the state of both the FPGA CI Test Shield
|
||||
* and the MbedTester object itself.
|
||||
*
|
||||
* Reset effects on the FPGA CI Test Shield include:
|
||||
* - All pins are tristated
|
||||
* - All pin mappings are reset
|
||||
* - All pullup/pulldown settings are reset
|
||||
* - All peripherals are reset
|
||||
*
|
||||
* Reset effects on the MbedTester object include
|
||||
* - Control channels tristated and freed
|
||||
* - Control channel selection set to automatic
|
||||
* - Most internal state reinitialized
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Reprogram the FPGA
|
||||
*
|
||||
* This function causes the FPGA to reboot and reload RAM contents.
|
||||
* This should be used after MbedTester::firmware_update to load the
|
||||
* new image.
|
||||
*/
|
||||
void reprogram();
|
||||
|
||||
/**
|
||||
* Get the running FPGA firmware version
|
||||
*
|
||||
* @return The version of firmware running on the FPGA.
|
||||
*
|
||||
*/
|
||||
uint32_t version();
|
||||
|
||||
/**
|
||||
* Select the currently active peripheral
|
||||
*
|
||||
* @param peripheral Active peripheral
|
||||
*/
|
||||
void select_peripheral(Peripheral peripheral);
|
||||
|
||||
/* **GPIO peripheral functions** */
|
||||
|
||||
/**
|
||||
* Read a gpio pin
|
||||
*
|
||||
* @param gpio Logical pin to read from
|
||||
* @return 1 if the pin is high 0 if the pin is low
|
||||
*/
|
||||
int gpio_read(LogicalPin gpio);
|
||||
|
||||
/**
|
||||
* Set value and drive of a gpio pin
|
||||
*
|
||||
* @param gpio Logical pin to write to
|
||||
* @param value 0 to set the pin low or non-zero to set it high
|
||||
* @param driver 0 to set the pin to Hi-Z or non-zero to drive the pin
|
||||
*/
|
||||
void gpio_write(LogicalPin gpio, int value, bool drive);
|
||||
|
||||
/* **IO Metrics functions** */
|
||||
|
||||
/**
|
||||
* Start recording metrics on all logical pins
|
||||
*
|
||||
* This function resets all past metrics to 0. To
|
||||
* preserve these call io_metrics_continue instead.
|
||||
*/
|
||||
void io_metrics_start();
|
||||
|
||||
/**
|
||||
* Stop recording metrics on all logical pins
|
||||
*
|
||||
* This function should be called before any metrics
|
||||
* are read to ensure the value does not change while
|
||||
* they are being read.
|
||||
*/
|
||||
void io_metrics_stop();
|
||||
|
||||
/**
|
||||
* Continue recording metrics on all logical pins
|
||||
*
|
||||
* Resume recording metrics.
|
||||
*/
|
||||
void io_metrics_continue();
|
||||
|
||||
/**
|
||||
* Get the shortest low pulse recorded
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The shortest number of 100MHz clock cycles the pin was low
|
||||
*/
|
||||
uint32_t io_metrics_min_pulse_low(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Get the shortest high pulse recorded
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The shortest number of 100MHz clock cycles the pin was high
|
||||
*/
|
||||
uint32_t io_metrics_min_pulse_high(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Get the longest low pulse recorded
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The longest number of 100MHz clock cycles the pin was low
|
||||
*/
|
||||
uint32_t io_metrics_max_pulse_low(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Get the longest high pulse recorded
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The longest number of 100MHz clock cycles the pin was high
|
||||
*/
|
||||
uint32_t io_metrics_max_pulse_high(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Get the number of rising edges
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The number of rising edges
|
||||
*/
|
||||
uint32_t io_metrics_rising_edges(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Get the number of falling edges
|
||||
*
|
||||
* @param pin Pin to read the metrics for
|
||||
* @return The number of falling edges
|
||||
*/
|
||||
uint32_t io_metrics_falling_edges(LogicalPin pin);
|
||||
|
||||
/**
|
||||
* Reset the IO expander modules
|
||||
*
|
||||
*/
|
||||
void pin_pull_reset_all();
|
||||
|
||||
/**
|
||||
* FPGA Pullup mode
|
||||
*/
|
||||
enum PullMode {
|
||||
PullUp,
|
||||
PullDown,
|
||||
PullNone
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure an Mbed pin for a pulldown resistor, pullup resistor, or tristate mode via PinName
|
||||
*
|
||||
* @param pin Mbed pin whose mode is being set
|
||||
* @param mode (MbedTester::PullUp, MbedTester::PullDown, or MbedTester::PullNone)
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int pin_set_pull(PinName pin, PullMode mode);
|
||||
|
||||
/**
|
||||
* Configure an Mbed pin for a pulldown resistor, pullup resistor, or tristate mode via pin index
|
||||
*
|
||||
* @param index Mbed pin index whose mode is being set
|
||||
* @param mode (MbedTester::PullUp, MbedTester::PullDown, or MbedTester::PullNone)
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int pin_set_pull_index(int index, PullMode mode);
|
||||
|
||||
/*
|
||||
* Register of the IO expander
|
||||
*/
|
||||
enum IOExpanderReg {
|
||||
RegInput,
|
||||
RegOutput,
|
||||
RegConfig
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a bit for a specific Mbed pin that is set in the input, output, or configuration registers inside of the IO expander via PinName
|
||||
*
|
||||
* @param pin Mbed pin whose register bit is being read
|
||||
* @param reg_type Pin register to access, options are: MbedTester::RegInput, MbedTester::RegOutput, or MbedTester::RegConfig
|
||||
* @return The value of the bit read
|
||||
*/
|
||||
uint8_t io_expander_read(PinName pin, IOExpanderReg reg_type);
|
||||
|
||||
/**
|
||||
* Read a bit for a specific Mbed pin that is set in the input, output, or configuration registers inside of the IO expander via pin index
|
||||
*
|
||||
* @param index Mbed pin index whose register bit is being read
|
||||
* @param reg_type Pin register to access, options are: MbedTester::RegInput, MbedTester::RegOutput, or MbedTester::RegConfig
|
||||
* @return The value of the bit read
|
||||
*/
|
||||
uint8_t io_expander_read_index(int index, IOExpanderReg reg_type);
|
||||
|
||||
/**
|
||||
* Configure an Mbed pin for a pulldown resistor, pullup resistor, or tristate mode
|
||||
* (this version of the function uses io_expander_i2c_read_bb and io_expander_i2c_write_bb)
|
||||
*
|
||||
* @param pin Mbed pin whose mode is being set
|
||||
* @param mode (MbedTester::PullUp, MbedTester::PullDown, or MbedTester::PullNone)
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int pin_set_pull_bb(PinName pin, PullMode mode);
|
||||
|
||||
/**
|
||||
* Read a bit for a specific Mbed pin that is set in the input, output, or configuration registers inside of the IO expander
|
||||
* (this version of the function uses io_expander_i2c_read_bb)
|
||||
*
|
||||
* @param pin Mbed pin whose register bit is being read
|
||||
* @param reg_type Pin register to access, options are: MbedTester::RegInput, MbedTester::RegOutput, or MbedTester::RegConfig
|
||||
* @return The value of the bit read
|
||||
*/
|
||||
uint8_t io_expander_read_bb(PinName pin, IOExpanderReg reg_type);
|
||||
|
||||
/**
|
||||
* Create an analog voltage via the FPGA sys pwm in order to test Mbed AnalogIn
|
||||
*
|
||||
* @param enable Enable the FPGA system PWM (false: of, true: on)
|
||||
* @param voltage The analog voltage that will be created by the FPGA CI test shield (float: 0.0 to 1.0)
|
||||
*/
|
||||
void set_analog_out(bool enable, float voltage);
|
||||
|
||||
/**
|
||||
* Turn the FPGA ADC on and off (power management data will be collected while the ADC is on)
|
||||
*
|
||||
* @param val FPGA ADC enable bit (false: off, true: on)
|
||||
*/
|
||||
void set_sample_adc(bool val);
|
||||
|
||||
/**
|
||||
* Get the result of the analog to digital conversion computed on the FPGA in the form of a voltage reading. The FPGA ADC operates on 0V-1V, which means this function will only ever return a float ranging from 0.0-1.0.
|
||||
*
|
||||
* @return The conversion result in the form of a voltage measurement for AnalogMuxIn, Eg. a return value of 0.7 means the ADC on the FPGA read 0.7 volts on its analog input
|
||||
*/
|
||||
float get_analog_in();
|
||||
|
||||
/**
|
||||
* Similar to 'get_analog_in' but returns a voltage reading from ANIN0-3
|
||||
*
|
||||
* @param index ANIN pin to read (0-3)
|
||||
* @return The conversion result in the form of a voltage measurement for ANIN0-3
|
||||
*/
|
||||
float get_anin_voltage(int index);
|
||||
|
||||
/* **Mid level system access** */
|
||||
|
||||
/*
|
||||
* These are the pins on the FPGA that are not connected to the Mbed board.
|
||||
* These can be controlled by using MbedTester::sys_pin_read and MbedTester::sys_pin_write.
|
||||
* These should not be used directly when using the FPGA CI Test Shield. The higher layer
|
||||
* APIs should be used instead.
|
||||
*/
|
||||
enum SystemPin {
|
||||
Reset,
|
||||
Reprogram,
|
||||
|
||||
DigitalID0,
|
||||
DigitalID1,
|
||||
DigitalID2,
|
||||
|
||||
Led0,
|
||||
Led1,
|
||||
Led2,
|
||||
Led3,
|
||||
|
||||
SPIIO0,
|
||||
SPIIO1,
|
||||
SPIIO2,
|
||||
SPIIO3,
|
||||
SPIClk,
|
||||
SPICS,
|
||||
|
||||
I2CReset,
|
||||
I2CSda0,
|
||||
I2CSda1,
|
||||
I2CSda2,
|
||||
I2CScl0,
|
||||
I2CScl1,
|
||||
I2CScl2,
|
||||
|
||||
AnalogMuxEnable,
|
||||
AnalogMuxPwmOut,
|
||||
AnalogMuxIn,
|
||||
AnalogMuxAddr0,
|
||||
AnalogMuxAddr1,
|
||||
AnalogMuxAddr2,
|
||||
AnalogMuxAddr3,
|
||||
AnalogMuxAddr4,
|
||||
AnalogMuxAddr5,
|
||||
AnalogMuxAddr6,
|
||||
AnalogMuxAddr7,
|
||||
|
||||
AnalogInP0,
|
||||
AnalogInP1,
|
||||
AnalogInP2,
|
||||
AnalogInP3,
|
||||
AnalogInN0,
|
||||
AnalogInN1,
|
||||
AnalogInN2,
|
||||
AnalogInN3,
|
||||
|
||||
SystemPinCount
|
||||
};
|
||||
|
||||
/**
|
||||
* Read from the given system pin
|
||||
*
|
||||
* @param pin The pin to read from
|
||||
* @return true if 1 was read, false if 0
|
||||
*/
|
||||
bool sys_pin_read(SystemPin pin);
|
||||
|
||||
/**
|
||||
* Write to the given system pin
|
||||
*
|
||||
* @param pin The pin to write to
|
||||
* @param value The value to output on the pin when driven
|
||||
* @param true to drive the output, false to set the output high-z
|
||||
* @return true if 1 was read, false if 0
|
||||
*/
|
||||
void sys_pin_write(SystemPin pin, int value, bool drive);
|
||||
|
||||
/**
|
||||
* I2C read on I2C system channels 0, 1, or 2
|
||||
*
|
||||
* @param i2c_index The number corresponding to the system i2c bus being used (0, 1, or 2)
|
||||
* @param dev_addr The I2C address of the device being read from
|
||||
* @param start_reg The internal device address where the read will start
|
||||
* @param data Data buffer for data to be read into
|
||||
* @param length The number of bytes to read
|
||||
* @return 0 on success (ACK), nonzero on failure (NACK)
|
||||
*/
|
||||
int io_expander_i2c_read(uint8_t i2c_index, uint8_t dev_addr, uint8_t start_reg, uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* I2C write on I2C system channels 0, 1, or 2
|
||||
*
|
||||
* @param i2c_index The number corresponding to the system i2c bus being used (0, 1, or 2)
|
||||
* @param dev_addr The I2C address of the device being written to
|
||||
* @param data The data to be written
|
||||
* @param length The number of bytes to be written
|
||||
* @return 0 on success (ACK), nonzero on failure (NACK)
|
||||
*/
|
||||
int io_expander_i2c_write(uint8_t i2c_index, uint8_t dev_addr, uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* I2C read on I2C system channels 0, 1, or 2
|
||||
* (bit banged version of function, bit banged over control channel)
|
||||
*
|
||||
* @param sda System pin used for sda
|
||||
* @param scl System pin used for scl
|
||||
* @param dev_addr The I2C address of the device being read from
|
||||
* @param start_reg The internal device address where the read will start
|
||||
* @param data Data buffer for data to be read into
|
||||
* @param length The number of bytes to read
|
||||
* @return 0 on success (ACK), nonzero on failure (NACK)
|
||||
*/
|
||||
int io_expander_i2c_read_bb(SystemPin sda, SystemPin scl, uint8_t dev_addr, uint8_t start_reg, uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* I2C write on I2C system channels 0, 1, or 2
|
||||
* (bit banged version of function, bit banged over control channel)
|
||||
*
|
||||
* @param sda System pin used for sda
|
||||
* @param scl System pin used for scl
|
||||
* @param dev_addr The I2C address of the device being written to
|
||||
* @param data The data to be written
|
||||
* @param length The number of bytes to be written
|
||||
* @return 0 on success (ACK), nonzero on failure (NACK)
|
||||
*/
|
||||
int io_expander_i2c_write_bb(SystemPin sda, SystemPin scl, uint8_t dev_addr, uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* Set the AnalogMuxAddr pins on the FPGA via PinName
|
||||
*
|
||||
* @param pin The Mbed pin that the analog signal will be routed to
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int set_mux_addr(PinName pin);
|
||||
|
||||
/**
|
||||
* Set the AnalogMuxAddr pins on the FPGA via pin index
|
||||
*
|
||||
* @param index The Mbed pin index that the analog signal will be routed to
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int set_mux_addr_index(int index);
|
||||
|
||||
/* **AnalogIn peripheral functions** */
|
||||
|
||||
/**
|
||||
* Turn on/off the analog muxes
|
||||
*
|
||||
* @param val false: off, true: on
|
||||
*/
|
||||
void set_mux_enable(bool val);
|
||||
|
||||
/**
|
||||
* Turn on/off pwm output on FPGA to test Mbed AnalogIn
|
||||
*
|
||||
* @param val false: off, true: on
|
||||
*/
|
||||
void set_pwm_enable(bool val);
|
||||
|
||||
/**
|
||||
* Check if FPGA pwm out is on or off
|
||||
*
|
||||
* @return FPGA enable bit (false: off, true: on)
|
||||
*/
|
||||
bool get_pwm_enable();
|
||||
|
||||
/**
|
||||
* Set the pwm output period and number of cycles high (duty cycle) on the FPGA
|
||||
*
|
||||
* @param period In units of clk cycles
|
||||
* @param cycles_high In units of clk cycles
|
||||
*/
|
||||
void set_pwm_period_and_cycles_high(uint32_t period, uint32_t cycles_high);
|
||||
|
||||
/**
|
||||
* Get the pwm output period of the FPGA
|
||||
*
|
||||
* @return FPGA pwm output period in units of clk cycles
|
||||
*/
|
||||
uint32_t get_pwm_period();
|
||||
|
||||
/**
|
||||
* Get the number of cycles that are high (duty cycle) from FPGA pwm
|
||||
*
|
||||
* @return FPGA pwm output cycles high
|
||||
*/
|
||||
uint8_t get_pwm_cycles_high();
|
||||
|
||||
/**
|
||||
* Get the 12-bit analog to digital conversion result from the FPGA
|
||||
*
|
||||
* @return 12-bit FPGA ADC result for AnalogMuxIn
|
||||
*/
|
||||
uint16_t get_analogmuxin_measurement();
|
||||
|
||||
/**
|
||||
* Similar to 'get_analogmuxin_measurement' but returns the current XADC measurement for ANIN0-3
|
||||
*
|
||||
* @param index ANIN pin to read (0-3)
|
||||
* @return 12-bit FPGA ADC result for ANIN0-3
|
||||
*/
|
||||
uint16_t get_anin_measurement(int index);
|
||||
|
||||
/**
|
||||
* Gets (by reference) the sum of all ANIN ADC results for any of the 4 ANIN pins specified by the index,
|
||||
* number of ADC sample sequences that have completed since the XADC was turned on, and the number of FPGA clk cycles
|
||||
* that have taken place since the ADC was turned on.
|
||||
*
|
||||
* @param index ANIN pin of which to get sum of results (0-3)
|
||||
* @param sum The sum of all specified ANIN pin's ADC results
|
||||
* @param samples The number of ADC sample sequences that have completed since the XADC was turned on
|
||||
* @param cycles The number of FPGA clk cycles that have taken place since the ADC was turned on
|
||||
*/
|
||||
void get_anin_sum_samples_cycles(int index, uint64_t *sum, uint32_t *samples, uint64_t *cycles);
|
||||
|
||||
/**
|
||||
* Allows safe reading of FPGA ADC related values while the FPGA ADC is on
|
||||
* If snapshot is set then the ADC values will be safely latched in the FPGA and safe to read.
|
||||
* The RTL will set snapshot to 0 after 1 clk cycle.
|
||||
*/
|
||||
void set_snapshot();
|
||||
|
||||
/**
|
||||
* Set the current system pin mode to disabled
|
||||
*
|
||||
* This releases any pin mappings that were set by the previous pin mode.
|
||||
*/
|
||||
void sys_pin_mode_disabled();
|
||||
|
||||
/**
|
||||
* Set the current system pin mode to serial flash
|
||||
*
|
||||
* Remap physical pins to the serial flash the FPGA boots from.
|
||||
* This is used for firmware updates.
|
||||
*
|
||||
* @param mosi The physical pin index to connect to serial flash mosi
|
||||
* @param miso The physical pin index to connect to serial flash miso
|
||||
* @param clk The physical pin index to connect to serial flash clk
|
||||
* @param ssel The physical pin index to connect to serial flash cs
|
||||
*/
|
||||
void sys_pin_mode_spi_serial_flash(PhysicalIndex mosi, PhysicalIndex miso, PhysicalIndex clk, PhysicalIndex ssel);
|
||||
|
||||
/**
|
||||
* Set the current system pin mode to io expander I2C bus
|
||||
*
|
||||
* Remap physical pins to the io expander I2C bus. The IO expanders
|
||||
* are used for setting pullups and pulldowns.
|
||||
*
|
||||
* @param index The index of the I2C bus to connect to
|
||||
* @param sda_in Physical pin index for the FPGA to output the state of SDA on
|
||||
* @param sda_val Physical pin index for the FPGA to read SDA from. When in this mode the Mbed board
|
||||
* must always drive this pin. Driving a 0 causes the FPGA to pull the SDA on the I2C bus low. Setting
|
||||
* a 1 causes the FPGA to let SDA on the I2C bus float (and get pulled to 1).
|
||||
* @param scl_in Physical pin index for the FPGA to output the state of SCL on
|
||||
* @param scl_val Physical pin index for the FPGA to read SCL from. When in this mode the Mbed board
|
||||
* must always drive this pin. Driving a 0 causes the FPGA to pull the SCL on the I2C bus low. Setting
|
||||
* a 1 causes the FPGA to let SDA on the SCL bus float (and get pulled to 1).
|
||||
*/
|
||||
void sys_pin_mode_i2c_io_expander(int index, PhysicalIndex sda_in, PhysicalIndex sda_val, PhysicalIndex scl_in, PhysicalIndex scl_val);
|
||||
|
||||
/**
|
||||
* Map a physical pin index to the given logical pin
|
||||
*
|
||||
* This function will automatically move the control channel
|
||||
* pins to avoid interfering with the mapped pin. The physical
|
||||
* pin index does not need to be part of the form factor.
|
||||
*
|
||||
* @param physical_index Index of the physical pin on the board
|
||||
* @param logical Logical pin to map to
|
||||
*/
|
||||
void pin_map_index(PhysicalIndex physical_index, LogicalPin logical);
|
||||
|
||||
|
||||
/* **Low level memory access** */
|
||||
|
||||
/**
|
||||
* Write to tester memory
|
||||
*
|
||||
* @addr addr Address to write to
|
||||
* @param data Data to write
|
||||
* @param size Number of bytes to write
|
||||
*/
|
||||
void write(uint32_t addr, const uint8_t *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* Read from tester memory
|
||||
*
|
||||
* @addr addr Address to read from
|
||||
* @param data Buffer to fill with data
|
||||
* @param size Number of bytes to read
|
||||
*/
|
||||
void read(uint32_t addr, uint8_t *data, uint32_t size);
|
||||
|
||||
/* **Self tests** */
|
||||
|
||||
/**
|
||||
* Run all self tests
|
||||
*
|
||||
* @return true if all self tests pass, false otherwise
|
||||
*/
|
||||
bool self_test_all();
|
||||
|
||||
/**
|
||||
* Test that all allowed control channels can be used
|
||||
*
|
||||
* Check that all pairs of clk and mosi which aren't in
|
||||
* the restricted list can be used.
|
||||
*
|
||||
* @note CLK and MOSI lines are paired, where CLK is always
|
||||
* on an even index and MOSI is always on an oddd index:
|
||||
* clk_index_N = N * 2
|
||||
* mosi_index_N = N * 2 + 1
|
||||
*
|
||||
* @note This functions sets the control pin management mode
|
||||
* to automatic when it completes.
|
||||
*
|
||||
* @return true if all control channel pairs (clk and mosi) of this
|
||||
* configuration can be used, false otherwise
|
||||
*/
|
||||
bool self_test_control_channels();
|
||||
|
||||
/**
|
||||
* Test that all allowed control miso lines can be used
|
||||
*
|
||||
* Check that every pin of this form factor aside from the
|
||||
* pins in the restricted list can be used as miso.
|
||||
*
|
||||
* @note This functions sets the control pin management mode
|
||||
* to automatic when it completes.
|
||||
*
|
||||
* @return true if all control channel miso lines of this
|
||||
* configuration can be used, false otherwise
|
||||
*/
|
||||
bool self_test_control_miso();
|
||||
|
||||
/**
|
||||
* Test that the current control channel works
|
||||
*
|
||||
* @return true if communication is successful, false otherwise
|
||||
*/
|
||||
bool self_test_control_current();
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Find suitable control pins
|
||||
*
|
||||
* This function finds the appropriate set of pins and test to ensure that communication with
|
||||
* the FPGA can be performed over them. Before calling this function MbedTester pins must be
|
||||
* freed by calling MbedTester::_free_control_pins.
|
||||
*
|
||||
* @param clk_out Clock pin to find and set
|
||||
* @param mosi_out Mosi pin to find and set
|
||||
* @param miso_out Miso pin to find and set
|
||||
* @param aux_out Aux pin to find and set
|
||||
* @return true if all pins were found, false otherwise
|
||||
*/
|
||||
bool _find_control_indexes(PhysicalIndex &clk_out, PhysicalIndex &mosi_out, PhysicalIndex &miso_out, PhysicalIndex &aux_out);
|
||||
|
||||
/*
|
||||
* Allocate control pins
|
||||
*
|
||||
* The pin indexes must already have been found
|
||||
*/
|
||||
void _setup_control_pins();
|
||||
|
||||
/*
|
||||
* Free control pins
|
||||
*
|
||||
* This function is safe to call even if the pins have been freed
|
||||
*/
|
||||
void _free_control_pins();
|
||||
|
||||
/*
|
||||
* Update the control channel if needed
|
||||
*
|
||||
* Open a control channel using allowed pins:
|
||||
* - Pin must be in the form factor
|
||||
* - Pin must not be in the exclude list
|
||||
* - Pin must not be mapped already
|
||||
*/
|
||||
void _update_control_pins();
|
||||
|
||||
/*
|
||||
* Check if this control channel needs to be updated
|
||||
*
|
||||
* @return true if the control channel needs to be updated, false otherwise
|
||||
*/
|
||||
bool _update_needed();
|
||||
|
||||
/*
|
||||
* Reset the state of the MbedTester class
|
||||
*
|
||||
* This does not effect the state of the FPGA in any way.
|
||||
*/
|
||||
void _reset();
|
||||
|
||||
PhysicalIndex _mapping[LogicalPinCount * (LogicalPinBanks + 1)];
|
||||
DynamicPinList _form_factor;
|
||||
DynamicPinList _exclude_pins;
|
||||
bool _control_auto;
|
||||
bool _control_valid;
|
||||
PhysicalIndex _clk_index;
|
||||
PhysicalIndex _mosi_index;
|
||||
PhysicalIndex _miso_index;
|
||||
PhysicalIndex _aux_index;
|
||||
mbed::DigitalInOut *_clk;
|
||||
mbed::DigitalInOut *_mosi;
|
||||
mbed::DigitalInOut *_miso;
|
||||
mbed::DigitalInOut *_aux;
|
||||
/*
|
||||
* Used to reset IO expander chips only once the first time
|
||||
* any IO expander is accessed as well as during an io_exp_test
|
||||
*/
|
||||
int _init_io_exp_rst_flag;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SPIMasterTester.h"
|
||||
#include "fpga_config.h"
|
||||
|
||||
uint16_t SPIMasterTester::get_transfer_count()
|
||||
{
|
||||
return SPITester::get_transfer_count(TESTER_SPI_MASTER_TRANSFERS, TESTER_SPI_MASTER_TRANSFERS_SIZE);
|
||||
}
|
||||
|
||||
uint32_t SPIMasterTester::get_receive_checksum()
|
||||
{
|
||||
return SPITester::get_receive_checksum(TESTER_SPI_MASTER_TO_SLAVE_CHECKSUM, TESTER_SPI_MASTER_TO_SLAVE_CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
void SPIMasterTester::set_mode(SPITester::SpiMode mode)
|
||||
{
|
||||
SPITester::set_mode(mode, TESTER_SPI_MASTER_CTRL, TESTER_SPI_MASTER_CTRL_SIZE, TESTER_SPI_MASTER_CLK_MODE_OFFSET, TESTER_SPI_MASTER_CLK_MODE_SIZE);
|
||||
}
|
||||
|
||||
void SPIMasterTester::set_bit_order(SPITester::SpiBitOrder bit_order)
|
||||
{
|
||||
SPITester::set_bit_order(bit_order, TESTER_SPI_MASTER_CTRL, TESTER_SPI_MASTER_CTRL_SIZE, TESTER_SPI_MASTER_BIT_ORDER_OFFSET, TESTER_SPI_MASTER_BIT_ORDER_SIZE);
|
||||
}
|
||||
|
||||
void SPIMasterTester::set_sym_size(uint32_t sym_size)
|
||||
{
|
||||
SPITester::set_sym_size(sym_size, TESTER_SPI_MASTER_CTRL, TESTER_SPI_MASTER_CTRL_SIZE, TESTER_SPI_MASTER_SYM_SIZE_OFFSET, TESTER_SPI_MASTER_SYM_SIZE_SIZE);
|
||||
}
|
||||
|
||||
void SPIMasterTester::set_duplex_mode(SPITester::SpiDuplex duplex)
|
||||
{
|
||||
SPITester::set_duplex_mode(duplex, TESTER_SPI_MASTER_CTRL, TESTER_SPI_MASTER_CTRL_SIZE, TESTER_SPI_MASTER_DUPLEX_OFFSET, TESTER_SPI_MASTER_DUPLEX_SIZE);
|
||||
}
|
||||
|
||||
void SPIMasterTester::set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt)
|
||||
{
|
||||
SPITester::set_hd_tx_rx_cnt(tx_cnt, rx_cnt, TESTER_SPI_MASTER_HD_RX_CNT, TESTER_SPI_MASTER_HD_RX_CNT_SIZE, TESTER_SPI_MASTER_HD_TX_CNT, TESTER_SPI_MASTER_HD_TX_CNT_SIZE);
|
||||
}
|
||||
|
||||
uint32_t SPIMasterTester::get_cs_to_first_clk_edge_ns()
|
||||
{
|
||||
uint32_t delay_ns;
|
||||
read(TESTER_SPI_MASTER_CS_TO_FIRST_SCLK_CNT, (uint8_t *)&delay_ns, TESTER_SPI_MASTER_CS_TO_FIRST_SCLK_CNT_SIZE);
|
||||
|
||||
return (delay_ns * 10);
|
||||
}
|
||||
|
||||
uint32_t SPIMasterTester::get_last_clk_edge_to_cs_ns()
|
||||
{
|
||||
uint32_t delay_ns;
|
||||
read(TESTER_SPI_MASTER_LAST_SCLK_TO_CS_CNT, (uint8_t *)&delay_ns, TESTER_SPI_MASTER_LAST_SCLK_TO_CS_CNT_SIZE);
|
||||
|
||||
return (delay_ns * 10);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPI_MASTER_TESTER_H
|
||||
#define SPI_MASTER_TESTER_H
|
||||
|
||||
#include "SPITester.h"
|
||||
|
||||
class SPIMasterTester: public SPITester {
|
||||
public:
|
||||
|
||||
SPIMasterTester(const PinList *form_factor, const PinList *exclude_pins)
|
||||
: SPITester(form_factor, exclude_pins)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the number of transfers which have occurred
|
||||
*
|
||||
* @return The number of SPI transfers that have completed since
|
||||
* spi was reset.
|
||||
*/
|
||||
uint16_t get_transfer_count();
|
||||
|
||||
/**
|
||||
* Read a checksum of data send to the tester
|
||||
*
|
||||
* @return The sum of all bytes sent to the tester since reset.
|
||||
*/
|
||||
uint32_t get_receive_checksum();
|
||||
|
||||
/**
|
||||
* Set the clock mode of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_mode(SpiMode mode);
|
||||
|
||||
/**
|
||||
* Set bit order durring transmission of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_bit_order(SpiBitOrder bit_order);
|
||||
|
||||
/**
|
||||
* Set symbol size used durring transmission of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_sym_size(uint32_t sym_size);
|
||||
|
||||
/**
|
||||
* Set full-duplex/half-duplex transmission mode of the spi_slave module.
|
||||
*
|
||||
* @param duplex duplex mode used for the transmission
|
||||
*/
|
||||
void set_duplex_mode(SpiDuplex duplex);
|
||||
|
||||
/**
|
||||
* Set tx/rx symbol count.
|
||||
*
|
||||
* @tx_cnt TX symbol count
|
||||
* @rx_cnt RX symbol count
|
||||
*
|
||||
* @note Required only in Half-Duplex mode.
|
||||
*/
|
||||
void set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt);
|
||||
|
||||
/**
|
||||
* Get nano seconds between chip select assertion and the first spi clock edge.
|
||||
*
|
||||
* @return nano seconds between chip select assertion and the first spi clock edge.
|
||||
*
|
||||
* @note Number of nano seconds is calculated based of number of counted clk changes and
|
||||
* clk frequency (100 MHz => 1 clk tick corresponds to 10 ns).
|
||||
* Accuracy of the returned value is +/- 10 ns.
|
||||
*/
|
||||
uint32_t get_cs_to_first_clk_edge_ns();
|
||||
|
||||
/**
|
||||
* Get nano seconds between last spi clock edge and chip select de-assertion.
|
||||
*
|
||||
* @return nano seconds between last spi clock edge and chip select de-assertion.
|
||||
*
|
||||
* @note Number of nano seconds is calculated based of number of counted clk changes and
|
||||
* clk frequency (100 MHz => 1 clk tick corresponds to 10 ns).
|
||||
* Accuracy of the returned value is +/- 10 ns.
|
||||
*/
|
||||
uint32_t get_last_clk_edge_to_cs_ns();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SPISlaveTester.h"
|
||||
#include "fpga_config.h"
|
||||
|
||||
uint16_t SPISlaveTester::get_transfer_count()
|
||||
{
|
||||
return SPITester::get_transfer_count(TESTER_SPI_SLAVE_TRANSFERS, TESTER_SPI_SLAVE_TRANSFERS_SIZE);
|
||||
}
|
||||
|
||||
uint32_t SPISlaveTester::get_receive_checksum()
|
||||
{
|
||||
return SPITester::get_receive_checksum(TESTER_SPI_SLAVE_TO_MASTER_CHECKSUM, TESTER_SPI_SLAVE_TO_MASTER_CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_mode(SPITester::SpiMode mode)
|
||||
{
|
||||
SPITester::set_mode(mode, TESTER_SPI_SLAVE_CTRL, TESTER_SPI_SLAVE_CTRL_SIZE, TESTER_SPI_SLAVE_CLK_MODE_OFFSET, TESTER_SPI_SLAVE_CLK_MODE_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_bit_order(SPITester::SpiBitOrder bit_order)
|
||||
{
|
||||
SPITester::set_bit_order(bit_order, TESTER_SPI_SLAVE_CTRL, TESTER_SPI_SLAVE_CTRL_SIZE, TESTER_SPI_SLAVE_BIT_ORDER_OFFSET, TESTER_SPI_SLAVE_BIT_ORDER_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_sym_size(uint32_t sym_size)
|
||||
{
|
||||
SPITester::set_sym_size(sym_size, TESTER_SPI_SLAVE_CTRL, TESTER_SPI_SLAVE_CTRL_SIZE, TESTER_SPI_SLAVE_SYM_SIZE_OFFSET, TESTER_SPI_SLAVE_SYM_SIZE_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_duplex_mode(SPITester::SpiDuplex duplex)
|
||||
{
|
||||
SPITester::set_duplex_mode(duplex, TESTER_SPI_SLAVE_CTRL, TESTER_SPI_SLAVE_CTRL_SIZE, TESTER_SPI_SLAVE_DUPLEX_OFFSET, TESTER_SPI_SLAVE_DUPLEX_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt)
|
||||
{
|
||||
SPITester::set_hd_tx_rx_cnt(tx_cnt, rx_cnt, TESTER_SPI_SLAVE_HD_RX_CNT, TESTER_SPI_SLAVE_HD_RX_CNT_SIZE, TESTER_SPI_SLAVE_HD_TX_CNT, TESTER_SPI_SLAVE_HD_TX_CNT_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_spi_master_freq(uint16_t clk_div)
|
||||
{
|
||||
write(TESTER_SPI_SLAVE_CLK_DIV, (uint8_t *)&clk_div, TESTER_SPI_SLAVE_CLK_DIV_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_num_of_symbols(uint16_t num_of_sym)
|
||||
{
|
||||
write(TESTER_SPI_SLAVE_NUM_OF_SYMBOLS, (uint8_t *)&num_of_sym, TESTER_SPI_SLAVE_NUM_OF_SYMBOLS_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_start_delay_us(uint8_t start_delay_us)
|
||||
{
|
||||
write(TESTER_SPI_SLAVE_START_DELAY_US, (uint8_t *)&start_delay_us, TESTER_SPI_SLAVE_START_DELAY_US_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::set_sym_delay_ns(uint16_t sym_delay_ns)
|
||||
{
|
||||
const uint16_t sym_delay_ticks = (sym_delay_ns + 9) / 10; // round up
|
||||
write(TESTER_SPI_SLAVE_SYM_DELAY_TICKS, (uint8_t *)&sym_delay_ticks, TESTER_SPI_SLAVE_SYM_DELAY_TICKS_SIZE);
|
||||
}
|
||||
|
||||
void SPISlaveTester::start_transfer()
|
||||
{
|
||||
uint32_t spi_ctrl = 0;
|
||||
read(TESTER_SPI_SLAVE_CTRL, (uint8_t *)&spi_ctrl, TESTER_SPI_SLAVE_CTRL_SIZE);
|
||||
spi_ctrl &= ~(((1 << TESTER_SPI_SLAVE_START_REQUEST_SIZE) - 1) << TESTER_SPI_SLAVE_START_REQUEST_OFFSET);
|
||||
spi_ctrl |= (1 << TESTER_SPI_SLAVE_START_REQUEST_OFFSET);
|
||||
write(TESTER_SPI_SLAVE_CTRL, (uint8_t *)&spi_ctrl, TESTER_SPI_SLAVE_CTRL_SIZE);
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPI_SLAVE_TESTER_H
|
||||
#define SPI_SLAVE_TESTER_H
|
||||
|
||||
#include "SPITester.h"
|
||||
|
||||
class SPISlaveTester: public SPITester {
|
||||
public:
|
||||
|
||||
SPISlaveTester(const PinList *form_factor, const PinList *exclude_pins)
|
||||
: SPITester(form_factor, exclude_pins)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the number of transfers which have occurred
|
||||
*
|
||||
* @return The number of SPI transfers that have completed since
|
||||
* spi was reset.
|
||||
*/
|
||||
uint16_t get_transfer_count();
|
||||
|
||||
/**
|
||||
* Read a checksum of data sent to the tester
|
||||
*
|
||||
* @return The sum of all bytes sent to the tester since reset.
|
||||
*/
|
||||
uint32_t get_receive_checksum();
|
||||
|
||||
/**
|
||||
* Set the clock mode of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_mode(SpiMode mode);
|
||||
|
||||
/**
|
||||
* Set bit order during transmission of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_bit_order(SpiBitOrder bit_order);
|
||||
|
||||
/**
|
||||
* Set symbol size used during transmission of the spi_slave module.
|
||||
*
|
||||
* @param mode Spi clock mode
|
||||
*/
|
||||
void set_sym_size(uint32_t sym_size);
|
||||
|
||||
/**
|
||||
* Set full-duplex/half-duplex transmission mode of the spi_slave module.
|
||||
*
|
||||
* @param duplex duplex mode used for the transmission
|
||||
*/
|
||||
void set_duplex_mode(SpiDuplex duplex);
|
||||
|
||||
/**
|
||||
* Set tx/rx symbol count.
|
||||
*
|
||||
* @tx_cnt TX symbol count
|
||||
* @rx_cnt RX symbol count
|
||||
*
|
||||
* @note Required only in Half-Duplex mode.
|
||||
*/
|
||||
void set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt);
|
||||
|
||||
/**
|
||||
* Set divisor to generate spi clock from FPGA base clock (100 MHz).
|
||||
*
|
||||
* @clk_div clock divisor.
|
||||
*/
|
||||
void set_spi_master_freq(uint16_t clk_div);
|
||||
|
||||
/**
|
||||
* Set number of symbols to be transmitted by spi master.
|
||||
*
|
||||
* @num_of_sym Number of symbols to be transmitted by spi master.
|
||||
*/
|
||||
void set_num_of_symbols(uint16_t num_of_sym);
|
||||
|
||||
/**
|
||||
* Set delay in us between start request and start of transmission.
|
||||
*
|
||||
* @start_delay_us Delay in us between start request and start of transmission.
|
||||
*/
|
||||
void set_start_delay_us(uint8_t start_delay_us);
|
||||
|
||||
/**
|
||||
* Set delay in ns between transmission of successive symbols.
|
||||
*
|
||||
* @sym_delay_ns Delay in ns between transmission of successive symbols.
|
||||
*/
|
||||
void set_sym_delay_ns(uint16_t sym_delay_ns);
|
||||
|
||||
/**
|
||||
* Request transmission start from FPGA master.
|
||||
*
|
||||
* @note Transmission will be started after the specified delay.
|
||||
*/
|
||||
void start_transfer();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SPITester.h"
|
||||
#include "fpga_config.h"
|
||||
|
||||
uint16_t SPITester::get_transfer_count(uint32_t addr_transfers, uint32_t size_transfers)
|
||||
{
|
||||
uint16_t transfers = 0;
|
||||
MBED_ASSERT(sizeof(transfers) == size_transfers);
|
||||
read(addr_transfers, (uint8_t *)&transfers, sizeof(transfers));
|
||||
return transfers;
|
||||
}
|
||||
|
||||
uint32_t SPITester::get_receive_checksum(uint32_t addr_checksum, uint32_t size_checksum)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
MBED_ASSERT(sizeof(checksum) == size_checksum);
|
||||
read(addr_checksum, (uint8_t *)&checksum, sizeof(checksum));
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void SPITester::set_mode(SPITester::SpiMode mode, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_clk_mode, uint32_t size_clk_mode)
|
||||
{
|
||||
uint32_t spi_ctrl = 0;
|
||||
read(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
spi_ctrl &= ~(((1 << size_clk_mode) - 1) << offset_clk_mode);
|
||||
spi_ctrl |= (mode << offset_clk_mode);
|
||||
write(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
}
|
||||
|
||||
void SPITester::set_bit_order(SPITester::SpiBitOrder bit_order, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_bit_order, uint32_t size_bit_order)
|
||||
{
|
||||
uint32_t spi_ctrl = 0;
|
||||
read(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
spi_ctrl &= ~(((1 << size_bit_order) - 1) << offset_bit_order);
|
||||
spi_ctrl |= (bit_order << offset_bit_order);
|
||||
write(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
}
|
||||
|
||||
void SPITester::set_sym_size(uint32_t sym_size, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_sym_size, uint32_t size_sym_size)
|
||||
{
|
||||
uint32_t spi_ctrl = 0;
|
||||
read(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
spi_ctrl &= ~(((1 << size_sym_size) - 1) << offset_sym_size) ;
|
||||
spi_ctrl |= (sym_size << offset_sym_size);
|
||||
write(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
}
|
||||
|
||||
void SPITester::set_duplex_mode(SPITester::SpiDuplex duplex, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_duplex, uint32_t size_duplex)
|
||||
{
|
||||
uint32_t spi_ctrl = 0;
|
||||
read(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
spi_ctrl &= ~(((1 << size_duplex) - 1) << offset_duplex);
|
||||
spi_ctrl |= (duplex << offset_duplex);
|
||||
write(addr_spi_ctrl, (uint8_t *)&spi_ctrl, size_spi_ctrl);
|
||||
}
|
||||
|
||||
void SPITester::set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt, uint32_t addr_hd_rx_cnt, uint32_t size_hd_rx_cnt, uint32_t addr_hd_tx_cnt, uint32_t size_hd_tx_cnt)
|
||||
{
|
||||
write(addr_hd_rx_cnt, (uint8_t *)&rx_cnt, size_hd_rx_cnt);
|
||||
write(addr_hd_tx_cnt, (uint8_t *)&tx_cnt, size_hd_tx_cnt);
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPI_TESTER_H
|
||||
#define SPI_TESTER_H
|
||||
|
||||
#include "MbedTester.h"
|
||||
|
||||
class SPITester: public MbedTester {
|
||||
public:
|
||||
|
||||
enum SpiMode {
|
||||
Mode0 = 0,
|
||||
Mode1 = 1,
|
||||
Mode2 = 2,
|
||||
Mode3 = 3
|
||||
};
|
||||
|
||||
enum SpiBitOrder {
|
||||
MSBFirst = 0,
|
||||
LSBFirst = 1
|
||||
};
|
||||
|
||||
enum SpiDuplex {
|
||||
FullDuplex = 0,
|
||||
HalfDuplex = 1
|
||||
};
|
||||
|
||||
SPITester(const PinList *form_factor, const PinList *exclude_pins)
|
||||
: MbedTester(form_factor, exclude_pins)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Read the number of transfers which have occurred
|
||||
*
|
||||
* return The number of SPI transfers that have completed since
|
||||
* spi was reset.
|
||||
*/
|
||||
uint16_t get_transfer_count(uint32_t addr_transfers, uint32_t size_transfers);
|
||||
|
||||
/*
|
||||
* Read a checksum of data send to the tester
|
||||
*
|
||||
* param addr_checksum Address of the FPGA checksum reg.
|
||||
* param size_checksum Size of the FPGA checksum reg.
|
||||
*
|
||||
* return The sum of all bytes sent to the tester since reset.
|
||||
*/
|
||||
uint32_t get_receive_checksum(uint32_t addr_checksum, uint32_t size_checksum);
|
||||
|
||||
/*
|
||||
* Set the clock mode of the spi_slave module.
|
||||
*
|
||||
* param mode Spi clock mode
|
||||
* param addr_spi_ctrl Address of the FPGA spi control reg.
|
||||
* param size_spi_ctrl Size of the FPGA FPGA spi control reg.
|
||||
* param offset_clk_mode Clock mode offset.
|
||||
* param size_clk_mode Clock mode size.
|
||||
*/
|
||||
void set_mode(SpiMode mode, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_clk_mode, uint32_t size_clk_mode);
|
||||
|
||||
/*
|
||||
* Set bit order durring transmission of the spi_slave module.
|
||||
*
|
||||
* param bit_order Spi clock mode
|
||||
* param addr_spi_ctrl Address of the FPGA spi control reg.
|
||||
* param size_spi_ctrl Size of the FPGA FPGA spi control reg.
|
||||
* param offset_bit_order Bit order offset.
|
||||
* param size_bit_order Bit order size.
|
||||
*/
|
||||
void set_bit_order(SpiBitOrder bit_order, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_bit_order, uint32_t size_bit_order);
|
||||
|
||||
/*
|
||||
* Set symbol size used durring transmission of the spi_slave module.
|
||||
*
|
||||
* param sym_size Spi symbol size
|
||||
* param addr_spi_ctrl Address of the FPGA spi control reg.
|
||||
* param size_spi_ctrl Size of the FPGA FPGA spi control reg.
|
||||
* param offset_sym_size Symbol size offset.
|
||||
* param size_sym_size Symbol size size.
|
||||
*/
|
||||
void set_sym_size(uint32_t sym_size, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_sym_size, uint32_t size_sym_size);
|
||||
|
||||
/*
|
||||
* Set full-duplex/half-duplex transmission mode of the spi_slave module.
|
||||
*
|
||||
* param duplex Duplex mode used for the transmission
|
||||
* param addr_spi_ctrl Address of the FPGA spi control reg.
|
||||
* param size_spi_ctrl Size of the FPGA FPGA spi control reg.
|
||||
* param offset_duplex Duplex mode offset.
|
||||
* param size_duplex Duplex mode size.
|
||||
*/
|
||||
void set_duplex_mode(SpiDuplex duplex, uint32_t addr_spi_ctrl, uint32_t size_spi_ctrl, uint32_t offset_duplex, uint32_t size_duplex);
|
||||
|
||||
/*
|
||||
* Set tx/rx symbol count.
|
||||
*
|
||||
* tx_cnt TX symbol count
|
||||
* rx_cnt RX symbol count
|
||||
* param addr_hd_rx_cnt Address of the FPGA half duplex RX count reg.
|
||||
* param size_hd_rx_cnt Size of the FPGA half duplex RX count reg.
|
||||
* param addr_hd_tx_cnt Address of the FPGA half duplex TX count reg.
|
||||
* param size_hd_tx_cnt Size of the FPGA half duplex TX count reg.
|
||||
*
|
||||
* note Required only in Half-Duplex mode.
|
||||
*/
|
||||
void set_hd_tx_rx_cnt(uint16_t tx_cnt, uint16_t rx_cnt, uint32_t addr_hd_rx_cnt, uint32_t size_hd_rx_cnt, uint32_t addr_hd_tx_cnt, uint32_t size_hd_tx_cnt);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UARTTester.h"
|
||||
#include "fpga_config.h"
|
||||
|
||||
void UARTTester::set_baud(uint32_t baudrate)
|
||||
{
|
||||
uint32_t divisor = TESTER_CLOCK_FREQUENCY_HZ / baudrate;
|
||||
// Baud divisor is only 16 bits
|
||||
MBED_ASSERT((divisor & 0xFFFF0000) == 0);
|
||||
write(TESTER_UART_BAUD_DIVISOR, (uint8_t *)&divisor, TESTER_UART_BAUD_DIVISOR_SIZE);
|
||||
}
|
||||
|
||||
void UARTTester::set_bits(uint8_t data_bits)
|
||||
{
|
||||
// Check for supported range
|
||||
MBED_ASSERT((data_bits >= 1) && (data_bits <= 16));
|
||||
write(TESTER_UART_BIT_COUNT, &data_bits, sizeof(data_bits));
|
||||
}
|
||||
|
||||
void UARTTester::set_stops(uint8_t stop_bits)
|
||||
{
|
||||
// Check for supported range
|
||||
MBED_ASSERT((stop_bits >= 1) && (stop_bits <= 16));
|
||||
write(TESTER_UART_STOP_COUNT, &stop_bits, sizeof(stop_bits));
|
||||
}
|
||||
|
||||
void UARTTester::set_parity(bool enable, bool odd_n_even)
|
||||
{
|
||||
uint8_t parity = (enable ? TESTER_UART_PARITY_ENABLE : 0) |
|
||||
(odd_n_even ? TESTER_UART_PARITY_ODD_N_EVEN : 0);
|
||||
write(TESTER_UART_PARITY, &parity, sizeof(parity));
|
||||
}
|
||||
|
||||
void UARTTester::rx_start()
|
||||
{
|
||||
uint8_t data = TESTER_UART_RX_CONTROL_ENABLE;
|
||||
write(TESTER_UART_RX_CONTROL, &data, sizeof(data));
|
||||
}
|
||||
|
||||
void UARTTester::rx_stop()
|
||||
{
|
||||
uint8_t data = 0;
|
||||
write(TESTER_UART_RX_CONTROL, &data, sizeof(data));
|
||||
}
|
||||
|
||||
uint32_t UARTTester::rx_get_checksum()
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
read(TESTER_UART_RX_CHECKSUM, (uint8_t *)&checksum, sizeof(checksum));
|
||||
return checksum;
|
||||
}
|
||||
|
||||
uint32_t UARTTester::rx_get_count()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
read(TESTER_UART_RX_COUNT, (uint8_t *)&count, sizeof(count));
|
||||
return count;
|
||||
}
|
||||
|
||||
uint16_t UARTTester::rx_get_data(int prev)
|
||||
{
|
||||
MBED_ASSERT((prev >= 1) && (prev <= 4));
|
||||
uint16_t data = 0;
|
||||
read(TESTER_UART_RX_PREV_1 - (prev - 1) * 2, (uint8_t *)&data, sizeof(data));
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t UARTTester::rx_get_parity_errors()
|
||||
{
|
||||
uint32_t errors = 0;
|
||||
read(TESTER_UART_RX_PARITY_ERRORS, (uint8_t *)&errors, sizeof(errors));
|
||||
return errors;
|
||||
}
|
||||
|
||||
uint32_t UARTTester::rx_get_stop_errors()
|
||||
{
|
||||
uint32_t errors = 0;
|
||||
read(TESTER_UART_RX_STOP_ERRORS, (uint8_t *)&errors, sizeof(errors));
|
||||
return errors;
|
||||
}
|
||||
|
||||
uint32_t UARTTester::rx_get_framing_errors()
|
||||
{
|
||||
uint32_t errors = 0;
|
||||
read(TESTER_UART_RX_FRAMING_ERRORS, (uint8_t *)&errors, sizeof(errors));
|
||||
return errors;
|
||||
}
|
||||
|
||||
void UARTTester::tx_start(bool cts_enabled)
|
||||
{
|
||||
uint32_t control = TESTER_UART_TX_CONTROL_ENABLE | (cts_enabled ? TESTER_UART_TX_CONTROL_ENABLE_CTS : 0);
|
||||
write(TESTER_UART_TX_CONTROL, (uint8_t *)&control, sizeof(control));
|
||||
}
|
||||
|
||||
void UARTTester::tx_stop()
|
||||
{
|
||||
uint32_t control = 0;
|
||||
write(TESTER_UART_TX_CONTROL, (uint8_t *)&control, sizeof(control));
|
||||
}
|
||||
|
||||
void UARTTester::tx_set_delay(uint32_t delay_ns)
|
||||
{
|
||||
uint32_t delay_clks = (delay_ns + TESTER_CLOCK_PERIOD_NS - 1) / TESTER_CLOCK_PERIOD_NS;
|
||||
write(TESTER_UART_TX_DELAY, (uint8_t *)&delay_clks, sizeof(delay_clks));
|
||||
}
|
||||
|
||||
void UARTTester::tx_set_count(uint32_t count)
|
||||
{
|
||||
write(TESTER_UART_TX_COUNT, (uint8_t *)&count, sizeof(count));
|
||||
}
|
||||
|
||||
void UARTTester::tx_set_next(uint16_t value)
|
||||
{
|
||||
write(TESTER_UART_TX_NEXT, (uint8_t *)&value, sizeof(value));
|
||||
}
|
||||
|
||||
void UARTTester::cts_deassert_delay(uint32_t delay_ns)
|
||||
{
|
||||
uint32_t delay_clks = delay_ns / TESTER_CLOCK_PERIOD_NS;
|
||||
write(TESTER_UART_CTS_DEACTIVATE_DELAY, (uint8_t *)&delay_clks, sizeof(delay_clks));
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef UART_TESTER_H
|
||||
#define UART_TESTER_H
|
||||
|
||||
#include "MbedTester.h"
|
||||
|
||||
|
||||
class UARTTester: public MbedTester {
|
||||
public:
|
||||
|
||||
UARTTester(const PinList *form_factor, const PinList *exclude_pins)
|
||||
: MbedTester(form_factor, exclude_pins)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the baudrate for uart TX and RX
|
||||
*
|
||||
* @param baudrate Target baudrate in HZ
|
||||
*/
|
||||
void set_baud(uint32_t baudrate);
|
||||
|
||||
/**
|
||||
* Set the number of data bits
|
||||
*
|
||||
* Supported values for data bits is 1 to 16
|
||||
*
|
||||
* @param data_bits The number of data bits in this transfer
|
||||
*/
|
||||
void set_bits(uint8_t data_bits);
|
||||
|
||||
/**
|
||||
* Set the number of stop bits
|
||||
*
|
||||
* Supported values for stop bits is 1 to 16
|
||||
*
|
||||
* @param stop_bits The number of stop bits to end the transfer with
|
||||
*/
|
||||
void set_stops(uint8_t stop_bits);
|
||||
|
||||
/**
|
||||
* Enable or disable parity checking
|
||||
*
|
||||
* @param enable true to enable parity checking, false to disable it
|
||||
* @param odd_n_even true of odd parity, false for even
|
||||
*/
|
||||
void set_parity(bool enable, bool odd_n_even);
|
||||
|
||||
/**
|
||||
* Enable UART reception
|
||||
*/
|
||||
void rx_start();
|
||||
|
||||
/**
|
||||
* Disable UART reception
|
||||
*/
|
||||
void rx_stop();
|
||||
|
||||
/**
|
||||
* Get the sum of all bytes received
|
||||
*
|
||||
* @return the sum of all bytes received
|
||||
*/
|
||||
uint32_t rx_get_checksum();
|
||||
|
||||
/**
|
||||
* Get the number of bytes received
|
||||
*
|
||||
* @return the number of bytes received
|
||||
*/
|
||||
uint32_t rx_get_count();
|
||||
|
||||
/**
|
||||
* Get the previous data(s) sent
|
||||
*
|
||||
* @param prev index of data to get 1 for the previous
|
||||
* @return data
|
||||
*/
|
||||
uint16_t rx_get_data(int prev = 1);
|
||||
|
||||
/**
|
||||
* Get the number of parity errors that have occurred
|
||||
*
|
||||
* @return number of parity errors that have occurred
|
||||
*/
|
||||
uint32_t rx_get_parity_errors();
|
||||
|
||||
/**
|
||||
* Get the number of stop errors that have occurred
|
||||
*
|
||||
* @return number of stop errors that have occurred
|
||||
*/
|
||||
uint32_t rx_get_stop_errors();
|
||||
|
||||
/**
|
||||
* Get the number of framing errors that have occurred
|
||||
*
|
||||
* @return number of framing errors that have occurred
|
||||
*/
|
||||
uint32_t rx_get_framing_errors();
|
||||
|
||||
/**
|
||||
* Start UART transmission
|
||||
*/
|
||||
void tx_start(bool cts_enabled = false);
|
||||
|
||||
/**
|
||||
* Stop UART transmission
|
||||
*/
|
||||
void tx_stop();
|
||||
|
||||
/**
|
||||
* Set the delay after the tx_start() call and before the actual start
|
||||
* of UART transmission
|
||||
*
|
||||
* @param delay in nanoseconds
|
||||
*/
|
||||
void tx_set_delay(uint32_t delay_ns);
|
||||
|
||||
/**
|
||||
* Set the number of bytes to send
|
||||
*
|
||||
* @param count Number of bytes to send when started
|
||||
*/
|
||||
void tx_set_count(uint32_t count);
|
||||
|
||||
/**
|
||||
* Set next sequence value to send
|
||||
*
|
||||
* When TX is started 'count' bytes will be sent. Each value will
|
||||
* be one greater than the previous.
|
||||
*
|
||||
* @param value Next value to send
|
||||
*/
|
||||
void tx_set_next(uint16_t value);
|
||||
|
||||
/**
|
||||
* Set the delay seen when deasserting the CTS line
|
||||
*
|
||||
* When delay is set to 0 then transmission will be immediately
|
||||
* stopped when CTS goes to 1.
|
||||
*
|
||||
* @param delay in nanoseconds
|
||||
*/
|
||||
void cts_deassert_delay(uint32_t delay_ns);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define TESTER_CLOCK_FREQUENCY_HZ 100000000
|
||||
#define TESTER_CLOCK_PERIOD_NS 10
|
||||
#define TESTER_CONTROL 0x00000000
|
||||
#define TESTER_CONTROL_RESET 0x00000000
|
||||
#define TESTER_CONTROL_RESET_PERIPHERALS (1 << 0)
|
||||
#define TESTER_CONTROL_RESET_ALL (1 << 1)
|
||||
#define TESTER_CONTROL_REPROGRAM (1 << 2)
|
||||
#define TESTER_CONTROL_VERSION 0x00000010
|
||||
#define TESTER_CONTROL_VERSION_SIZE 4
|
||||
#define TESTER_REMAP 0x00001000
|
||||
#define TESTER_SYS_IO 0x00002000
|
||||
#define TESTER_SYS_IO_MODE (0x000 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_MODE_DISABLED 0
|
||||
#define TESTER_SYS_IO_MODE_SPI_SERIAL_FLASH 1
|
||||
#define TESTER_SYS_IO_MODE_I2C_IO_EXPANDER0 2
|
||||
#define TESTER_SYS_IO_MODE_I2C_IO_EXPANDER1 3
|
||||
#define TESTER_SYS_IO_MODE_I2C_IO_EXPANDER2 4
|
||||
#define TESTER_SYS_IO_PWM_ENABLE (0x001 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_PWM_PERIOD (0x002 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_PWM_CYCLES_HIGH (0x006 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_AN_MUX_ANALOGIN_MEASUREMENT (0x00A + 0x00002C00)
|
||||
#define TESTER_SYS_IO_NUM_POWER_SAMPLES (0x00C + 0x00002C00)
|
||||
#define TESTER_SYS_IO_NUM_POWER_CYCLES (0x010 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ADC_SNAPSHOT (0x018 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_SAMPLE_ADC (0x019 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN0_MEASUREMENT (0x030 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN0_MEASUREMENTS_SUM (0x032 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN1_MEASUREMENT (0x03A + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN1_MEASUREMENTS_SUM (0x03C + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN2_MEASUREMENT (0x044 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN2_MEASUREMENTS_SUM (0x046 + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN3_MEASUREMENT (0x04E + 0x00002C00)
|
||||
#define TESTER_SYS_IO_ANIN3_MEASUREMENTS_SUM (0x050 + 0x00002C00)
|
||||
#define TESTER_PERIPHERAL 0x00100000
|
||||
#define TESTER_PERIPHERAL_SELECT 0x00100000
|
||||
#define TESTER_GPIO 0x00101000
|
||||
#define TESTER_SPI_MASTER 0x00102000
|
||||
#define TESTER_SPI_MASTER_STARTS 0x00102008
|
||||
#define TESTER_SPI_MASTER_STOPS 0x00102009
|
||||
#define TESTER_SPI_MASTER_TRANSFERS 0x0010200A
|
||||
#define TESTER_SPI_MASTER_TRANSFERS_SIZE 2
|
||||
#define TESTER_SPI_MASTER_TO_SLAVE_CHECKSUM 0x00102012
|
||||
#define TESTER_SPI_MASTER_TO_SLAVE_CHECKSUM_SIZE 4
|
||||
#define TESTER_SPI_MASTER_CTRL 0x00102016
|
||||
#define TESTER_SPI_MASTER_CTRL_SIZE 2
|
||||
#define TESTER_SPI_MASTER_HD_TX_CNT 0x00102018
|
||||
#define TESTER_SPI_MASTER_HD_TX_CNT_SIZE 2
|
||||
#define TESTER_SPI_MASTER_HD_RX_CNT 0x0010201A
|
||||
#define TESTER_SPI_MASTER_HD_RX_CNT_SIZE 2
|
||||
#define TESTER_SPI_MASTER_CS_TO_FIRST_SCLK_CNT 0x0010201C
|
||||
#define TESTER_SPI_MASTER_CS_TO_FIRST_SCLK_CNT_SIZE 4
|
||||
#define TESTER_SPI_MASTER_LAST_SCLK_TO_CS_CNT 0x00102020
|
||||
#define TESTER_SPI_MASTER_LAST_SCLK_TO_CS_CNT_SIZE 4
|
||||
#define TESTER_SPI_MASTER_CLK_MODE_OFFSET 0
|
||||
#define TESTER_SPI_MASTER_CLK_MODE_SIZE 2
|
||||
#define TESTER_SPI_MASTER_BIT_ORDER_OFFSET 2
|
||||
#define TESTER_SPI_MASTER_BIT_ORDER_SIZE 1
|
||||
#define TESTER_SPI_MASTER_DUPLEX_OFFSET 3
|
||||
#define TESTER_SPI_MASTER_DUPLEX_SIZE 1
|
||||
#define TESTER_SPI_MASTER_SYM_SIZE_OFFSET 4
|
||||
#define TESTER_SPI_MASTER_SYM_SIZE_SIZE 6
|
||||
#define TESTER_SPI_SLAVE 0x00106000
|
||||
#define TESTER_SPI_SLAVE_STARTS 0x00106008
|
||||
#define TESTER_SPI_SLAVE_STOPS 0x00106009
|
||||
#define TESTER_SPI_SLAVE_TRANSFERS 0x0010600A
|
||||
#define TESTER_SPI_SLAVE_TRANSFERS_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_TO_MASTER_CHECKSUM 0x00106015
|
||||
#define TESTER_SPI_SLAVE_TO_MASTER_CHECKSUM_SIZE 4
|
||||
#define TESTER_SPI_SLAVE_CTRL 0x00106019
|
||||
#define TESTER_SPI_SLAVE_CTRL_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_HD_TX_CNT 0x0010601B
|
||||
#define TESTER_SPI_SLAVE_HD_TX_CNT_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_HD_RX_CNT 0x0010601D
|
||||
#define TESTER_SPI_SLAVE_HD_RX_CNT_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_CLK_DIV 0x0010601F
|
||||
#define TESTER_SPI_SLAVE_CLK_DIV_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_NUM_OF_SYMBOLS 0x00106021
|
||||
#define TESTER_SPI_SLAVE_NUM_OF_SYMBOLS_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_START_DELAY_US 0x00106023
|
||||
#define TESTER_SPI_SLAVE_START_DELAY_US_SIZE 1
|
||||
#define TESTER_SPI_SLAVE_SYM_DELAY_TICKS 0x00106024
|
||||
#define TESTER_SPI_SLAVE_SYM_DELAY_TICKS_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_CLK_MODE_OFFSET 0
|
||||
#define TESTER_SPI_SLAVE_CLK_MODE_SIZE 2
|
||||
#define TESTER_SPI_SLAVE_BIT_ORDER_OFFSET 2
|
||||
#define TESTER_SPI_SLAVE_BIT_ORDER_SIZE 1
|
||||
#define TESTER_SPI_SLAVE_DUPLEX_OFFSET 3
|
||||
#define TESTER_SPI_SLAVE_DUPLEX_SIZE 1
|
||||
#define TESTER_SPI_SLAVE_SYM_SIZE_OFFSET 4
|
||||
#define TESTER_SPI_SLAVE_SYM_SIZE_SIZE 6
|
||||
#define TESTER_SPI_SLAVE_START_REQUEST_OFFSET 10
|
||||
#define TESTER_SPI_SLAVE_START_REQUEST_SIZE 1
|
||||
#define TESTER_IO_METRICS 0x00103000
|
||||
#define TESTER_IO_METRICS_CTRL 0x00103000
|
||||
#define TESTER_IO_METRICS_CTRL_ACTIVE_BIT (1 << 0)
|
||||
#define TESTER_IO_METRICS_CTRL_RESET_BIT (1 << 1)
|
||||
#define TESTER_IO_METRICS_BASE(i) (0x00103040 + 0x40 * (i))
|
||||
#define TESTER_IO_METRICS_MIN_PULSE_LOW(i) (TESTER_IO_METRICS_BASE(i) + 0x00)
|
||||
#define TESTER_IO_METRICS_MIN_PULSE_LOW_SIZE 4
|
||||
#define TESTER_IO_METRICS_MIN_PULSE_HIGH(i) (TESTER_IO_METRICS_BASE(i) + 0x04)
|
||||
#define TESTER_IO_METRICS_MIN_PULSE_HIGH_SIZE 4
|
||||
#define TESTER_IO_METRICS_MAX_PULSE_LOW(i) (TESTER_IO_METRICS_BASE(i) + 0x08)
|
||||
#define TESTER_IO_METRICS_MAX_PULSE_LOW_SIZE 4
|
||||
#define TESTER_IO_METRICS_MAX_PULSE_HIGH(i) (TESTER_IO_METRICS_BASE(i) + 0x0C)
|
||||
#define TESTER_IO_METRICS_MAX_PULSE_HIGH_SIZE 4
|
||||
#define TESTER_IO_METRICS_RISING_EDGES(i) (TESTER_IO_METRICS_BASE(i) + 0x10)
|
||||
#define TESTER_IO_METRICS_RISING_EDGES_SIZE 4
|
||||
#define TESTER_IO_METRICS_FALLING_EDGES(i) (TESTER_IO_METRICS_BASE(i) + 0x14)
|
||||
#define TESTER_IO_METRICS_FALLING_EDGES_SIZE 4
|
||||
#define TESTER_UART_CONTROL (0x000 + 0x00104000)
|
||||
#define TESTER_UART_CONTROL_SIZE 4
|
||||
#define TESTER_UART_BAUD_DIVISOR (0x004 + 0x00104000)
|
||||
#define TESTER_UART_BAUD_DIVISOR_SIZE 2
|
||||
#define TESTER_UART_BIT_COUNT (0x010 + 0x00104000)
|
||||
#define TESTER_UART_BIT_COUNT_SIZE 1
|
||||
#define TESTER_UART_STOP_COUNT (0x011 + 0x00104000)
|
||||
#define TESTER_UART_STOP_COUNT_SIZE 1
|
||||
#define TESTER_UART_PARITY (0x012 + 0x00104000)
|
||||
#define TESTER_UART_PARITY_SIZE 1
|
||||
#define TESTER_UART_PARITY_ENABLE (1 << 0)
|
||||
#define TESTER_UART_PARITY_ODD_N_EVEN (1 << 1)
|
||||
#define TESTER_UART_RX_CONTROL (0x100 + 0x00104000)
|
||||
#define TESTER_UART_RX_CONTROL_SIZE 4
|
||||
#define TESTER_UART_RX_CONTROL_ENABLE (1 << 0)
|
||||
#define TESTER_UART_RX_CONTROL_RESET (1 << 1)
|
||||
#define TESTER_UART_RX_CHECKSUM (0x104 + 0x00104000)
|
||||
#define TESTER_UART_RX_CHECKSUM_SIZE 4
|
||||
#define TESTER_UART_RX_COUNT (0x108 + 0x00104000)
|
||||
#define TESTER_UART_RX_COUNT_SIZE 4
|
||||
#define TESTER_UART_RX_PARITY_ERRORS (0x10C + 0x00104000)
|
||||
#define TESTER_UART_RX_PARITY_ERRORS_SIZE 4
|
||||
#define TESTER_UART_RX_STOP_ERRORS (0x110 + 0x00104000)
|
||||
#define TESTER_UART_RX_STOP_ERRORS_SIZE 4
|
||||
#define TESTER_UART_RX_FRAMING_ERRORS (0x114 + 0x00104000)
|
||||
#define TESTER_UART_RX_FRAMING_ERRORS_SIZE 4
|
||||
#define TESTER_UART_RX_PREV_4 (0x118 + 0x00104000)
|
||||
#define TESTER_UART_RX_PREV_4_SIZE 2
|
||||
#define TESTER_UART_RX_PREV_3 (0x11A + 0x00104000)
|
||||
#define TESTER_UART_RX_PREV_3_SIZE 2
|
||||
#define TESTER_UART_RX_PREV_2 (0x11C + 0x00104000)
|
||||
#define TESTER_UART_RX_PREV_2_SIZE 2
|
||||
#define TESTER_UART_RX_PREV_1 (0x11E + 0x00104000)
|
||||
#define TESTER_UART_RX_PREV_1_SIZE 2
|
||||
#define TESTER_UART_TX_CONTROL (0x200 + 0x00104000)
|
||||
#define TESTER_UART_TX_CONTROL_SIZE 4
|
||||
#define TESTER_UART_TX_CONTROL_ENABLE (1 << 0)
|
||||
#define TESTER_UART_TX_CONTROL_RESET (1 << 1)
|
||||
#define TESTER_UART_TX_CONTROL_ENABLE_CTS (1 << 2)
|
||||
#define TESTER_UART_TX_COUNT (0x204 + 0x00104000)
|
||||
#define TESTER_UART_TX_COUNT_SIZE 4
|
||||
#define TESTER_UART_TX_NEXT (0x208 + 0x00104000)
|
||||
#define TESTER_UART_TX_NEXT_SIZE 2
|
||||
#define TESTER_UART_CTS_DEACTIVATE_DELAY (0x210 + 0x00104000)
|
||||
#define TESTER_UART_CTS_DEACTIVATE_DELAY_SIZE 4
|
||||
#define TESTER_UART_TX_DELAY (0x214 + 0x00104000)
|
||||
#define TESTER_UART_TX_DELAY_SIZE 4
|
||||
#define TESTER_I2C_STARTS (0x000 + 0x00105000)
|
||||
#define TESTER_I2C_STOPS (0x001 + 0x00105000)
|
||||
#define TESTER_I2C_ACKS (0x002 + 0x00105000)
|
||||
#define TESTER_I2C_NACKS (0x004 + 0x00105000)
|
||||
#define TESTER_I2C_TRANSFERS (0x006 + 0x00105000)
|
||||
#define TESTER_I2C_TRANSFERS_SIZE 2
|
||||
#define TESTER_I2C_TO_SLAVE_CHECKSUM (0x008 + 0x00105000)
|
||||
#define TESTER_I2C_TO_SLAVE_CHECKSUM_SIZE 4
|
||||
#define TESTER_I2C_STATE_NUM (0x00C + 0x00105000)
|
||||
#define TESTER_I2C_NUMBER_DEV_ADDR_MATCHES (0x00D + 0x00105000)
|
||||
#define TESTER_I2C_DEVICE_ADDRESS (0x00E + 0x00105000)
|
||||
#define TESTER_I2C_SET_SDA (0x010 + 0x00105000)
|
||||
#define TESTER_I2C_PREV_TO_SLAVE_4 (0x011 + 0x00105000)
|
||||
#define TESTER_I2C_PREV_TO_SLAVE_3 (0x012 + 0x00105000)
|
||||
#define TESTER_I2C_PREV_TO_SLAVE_2 (0x013 + 0x00105000)
|
||||
#define TESTER_I2C_PREV_TO_SLAVE_1 (0x014 + 0x00105000)
|
||||
#define TESTER_I2C_NEXT_FROM_SLAVE (0x015 + 0x00105000)
|
||||
#define TESTER_I2C_NUM_WRITES (0x016 + 0x00105000)
|
||||
#define TESTER_I2C_NUM_READS (0x018 + 0x00105000)
|
|
@ -0,0 +1,535 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TEST_UTILS_H
|
||||
#define TEST_UTILS_H
|
||||
|
||||
#include <list>
|
||||
|
||||
// test function prototypes
|
||||
typedef void (*TF1)(PinName p0);
|
||||
typedef void (*TF2)(PinName p0, PinName p1);
|
||||
typedef void (*TF3)(PinName p0, PinName p1, PinName p2);
|
||||
typedef void (*TF4)(PinName p0, PinName p1, PinName p2, PinName p3);
|
||||
typedef void (*TF5)(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4);
|
||||
|
||||
template<typename PortType, typename FunctionType, FunctionType f>
|
||||
struct FunctionCaller {
|
||||
|
||||
};
|
||||
|
||||
template<typename PortType, TF1 f>
|
||||
struct FunctionCaller<PortType, TF1, f> {
|
||||
void operator()(PortType &port)
|
||||
{
|
||||
f(port.pins[0]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PortType, TF2 f>
|
||||
struct FunctionCaller<PortType, TF2, f> {
|
||||
void operator()(PortType &port)
|
||||
{
|
||||
f(port.pins[0], port.pins[1]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PortType, TF3 f>
|
||||
struct FunctionCaller<PortType, TF3, f> {
|
||||
void operator()(PortType &port)
|
||||
{
|
||||
f(port.pins[0], port.pins[1], port.pins[2]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PortType, TF4 f>
|
||||
struct FunctionCaller<PortType, TF4, f> {
|
||||
void operator()(PortType &port)
|
||||
{
|
||||
f(port.pins[0], port.pins[1], port.pins[2], port.pins[3]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PortType, TF5 f>
|
||||
struct FunctionCaller<PortType, TF5, f> {
|
||||
void operator()(PortType &port)
|
||||
{
|
||||
f(port.pins[0], port.pins[1], port.pins[2], port.pins[3], port.pins[4]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PortType>
|
||||
bool peripheral_comparator(const PortType &port1, const PortType &port2)
|
||||
{
|
||||
return port1.peripheral == port2.peripheral;
|
||||
}
|
||||
|
||||
template <typename PortType>
|
||||
bool peripheral_less(const PortType &port1, const PortType &port2)
|
||||
{
|
||||
return port1.peripheral < port2.peripheral;
|
||||
}
|
||||
|
||||
template<typename PortType, typename FormFactorType>
|
||||
static bool find_port_pins(PortType &port)
|
||||
{
|
||||
return pinmap_find_peripheral_pins(FormFactorType::pins(), FormFactorType::restricted_pins(),
|
||||
port.peripheral, PortType::PinMap::maps, port.ppins, PortType::pin_count);
|
||||
}
|
||||
|
||||
template<typename PortType, typename FormFactorType>
|
||||
void find_ports(std::list<PortType> &matched_ports, std::list<PortType> ¬_matched_ports)
|
||||
{
|
||||
// Loop through every pin type
|
||||
for (uint32_t i = 0; i < PortType::pin_count; i++) {
|
||||
const PinMap *map = PortType::PinMap::maps[i];
|
||||
const char *pin_type = PortType::PinMap::pin_type_names[i];
|
||||
|
||||
// Loop through each pin of a given type
|
||||
for (; map->pin != NC; map++) {
|
||||
PortType port;
|
||||
// Set pin being tested
|
||||
port.pins[i] = map->pin;
|
||||
port.peripheral = map->peripheral;
|
||||
// Only form factor pins can be tested
|
||||
if (!pinmap_list_has_pin(FormFactorType::pins(), port.pins[i])) {
|
||||
continue;
|
||||
}
|
||||
// Don't test restricted pins
|
||||
if (pinmap_list_has_pin(FormFactorType::restricted_pins(), port.pins[i])) {
|
||||
utest_printf("Skipping %s pin %s (%i)\r\n", pin_type,
|
||||
FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
|
||||
continue;
|
||||
}
|
||||
// skipp pin searching if single pin port type
|
||||
if (PortType::pin_count > 1) {
|
||||
find_port_pins<PortType, FormFactorType>(port);
|
||||
}
|
||||
if (port.empty()) {
|
||||
not_matched_ports.push_back(port);
|
||||
} else {
|
||||
matched_ports.push_back(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename PortType, typename FormFactorType, typename FunctionType, FunctionType f>
|
||||
void test_all_ports(std::list<PortType> &matched_ports, std::list<PortType> ¬_matched_ports)
|
||||
{
|
||||
typedef typename std::list<PortType>::iterator Iter;
|
||||
utest_printf("***Testing %s on all form factor ports***\n", PortType::PinMap::name);
|
||||
const PinList *ff_pins = FormFactorType::pins();
|
||||
FunctionCaller<PortType, FunctionType, f> call;
|
||||
|
||||
if (matched_ports.empty() && not_matched_ports.empty()) {
|
||||
utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ff_pins->count; i++) {
|
||||
for (Iter it = matched_ports.begin(); it != matched_ports.end(); ++it) {
|
||||
PortType &port = *it;
|
||||
for (uint32_t j = 0; j < PortType::pin_count; j++) {
|
||||
if (ff_pins->pins[i] == port.pins[j]) {
|
||||
utest_printf("%3s - %s pin tested on port: %s...", FormFactorType::pin_to_string(ff_pins->pins[i]),
|
||||
PortType::PinMap::pin_type_names[j], port.str());
|
||||
if (port.status == PortType::StatusNotTested) {
|
||||
call(port);
|
||||
port.status = PortType::StatusPass;
|
||||
}
|
||||
utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
|
||||
goto end_port_iteration;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Iter it = not_matched_ports.begin(); it != not_matched_ports.end(); ++it) {
|
||||
PortType &port = *it;
|
||||
for (uint32_t j = 0; j < PortType::pin_count; j++) {
|
||||
if (ff_pins->pins[i] == port.pins[j]) {
|
||||
utest_printf("%3s - Could not find pins to test %s pin %s (%d)\n",
|
||||
FormFactorType::pin_to_string(ff_pins->pins[i]),
|
||||
PortType::PinMap::pin_type_names[j],
|
||||
FormFactorType::pin_to_string(ff_pins->pins[i]),
|
||||
ff_pins->pins[i]);
|
||||
goto end_port_iteration;
|
||||
}
|
||||
}
|
||||
}
|
||||
end_port_iteration:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PortType, typename FunctionType, FunctionType f>
|
||||
void test_peripheral(PortType &port)
|
||||
{
|
||||
if (port.empty()) {
|
||||
utest_printf("%d - Could not find pins to test peripheral\n", port.peripheral);
|
||||
} else {
|
||||
utest_printf("%d - peripheral tested on port: %s...", port.peripheral, port.str());
|
||||
if (port.status == PortType::StatusNotTested) {
|
||||
FunctionCaller<PortType, FunctionType, f> call;
|
||||
call(port); // run test
|
||||
port.status = PortType::StatusPass;
|
||||
}
|
||||
utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PortType, typename FunctionType, FunctionType f>
|
||||
void test_all_peripherals(std::list<PortType> &matched_ports, std::list<PortType> ¬_matched_ports)
|
||||
{
|
||||
typedef typename std::list<PortType>::iterator Iter;
|
||||
utest_printf("***Testing all %s peripherals***\n", PortType::PinMap::name);
|
||||
|
||||
if (matched_ports.empty() && not_matched_ports.empty()) {
|
||||
utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
|
||||
return;
|
||||
}
|
||||
|
||||
matched_ports.sort(peripheral_less<PortType>);
|
||||
not_matched_ports.sort(peripheral_less<PortType>);
|
||||
|
||||
for (Iter m_it = matched_ports.begin(), nm_it = not_matched_ports.begin();
|
||||
m_it != matched_ports.end() || nm_it != not_matched_ports.end();) {
|
||||
if (m_it != matched_ports.end() && nm_it != not_matched_ports.end()) {
|
||||
if ((*m_it).peripheral < (*nm_it).peripheral) {
|
||||
test_peripheral<PortType, FunctionType, f>(*m_it);
|
||||
++m_it;
|
||||
} else {
|
||||
test_peripheral<PortType, FunctionType, f>(*nm_it);
|
||||
++nm_it;
|
||||
}
|
||||
} else if (m_it != matched_ports.end()) {
|
||||
test_peripheral<PortType, FunctionType, f>(*m_it);
|
||||
++m_it;
|
||||
} else if (nm_it != not_matched_ports.end()) {
|
||||
test_peripheral<PortType, FunctionType, f>(*nm_it);
|
||||
++nm_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function for all pinouts of all peripherals of a given type
|
||||
*
|
||||
* This template function takes in three template parameters:
|
||||
* - PortType - The type of peripheral to test
|
||||
* - FormFactorType - The form factor to test on
|
||||
* - f - The test function to run.
|
||||
*
|
||||
* This function is calls the test function multiple times with
|
||||
* the appropriate combinations of pins.
|
||||
*/
|
||||
template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
|
||||
void all_ports()
|
||||
{
|
||||
std::list<PortType> matched_ports, not_matched_ports;
|
||||
find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
|
||||
matched_ports.unique();
|
||||
not_matched_ports.unique();
|
||||
test_all_ports<PortType, FormFactorType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function for one pinout of all peripherals of a given type
|
||||
*
|
||||
* This template function takes in three template parameters:
|
||||
* - PortType - The type of peripheral to test
|
||||
* - FormFactorType - The form factor to test on
|
||||
* - f - The test function to run.
|
||||
*
|
||||
* This function is calls the test function once for each peripheral
|
||||
* of the given type.
|
||||
*/
|
||||
template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
|
||||
void all_peripherals()
|
||||
{
|
||||
std::list<PortType> matched_ports, not_matched_ports;
|
||||
find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
|
||||
|
||||
matched_ports.sort(peripheral_less<PortType>);
|
||||
not_matched_ports.sort(peripheral_less<PortType>);
|
||||
matched_ports.unique(peripheral_comparator<PortType>);
|
||||
not_matched_ports.unique(peripheral_comparator<PortType>);
|
||||
|
||||
test_all_peripherals<PortType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function for one pinout of one peripheral of a given type
|
||||
*
|
||||
* This template function takes in three template parameters:
|
||||
* - PortType - The type of peripheral to test
|
||||
* - FormFactorType - The form factor to test on
|
||||
* - f - The test function to run.
|
||||
*
|
||||
* This function is calls the test function once for one peripheral
|
||||
* of the given type.
|
||||
*/
|
||||
template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
|
||||
void one_peripheral()
|
||||
{
|
||||
std::list<PortType> matched_ports, not_matched_ports;
|
||||
find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
|
||||
|
||||
utest_printf("***Testing one %s pin configuration***\n", PortType::PinMap::name);
|
||||
if (matched_ports.empty()) {
|
||||
utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
|
||||
} else {
|
||||
test_peripheral<PortType, typename PortType::TestFunctionType, f>(matched_ports.front());
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
|
||||
class Port;
|
||||
|
||||
template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
|
||||
bool operator== (const Port<N, PinMapType, FormFactorType, TestFunctionType> &port1,
|
||||
const Port<N, PinMapType, FormFactorType, TestFunctionType> &port2);
|
||||
|
||||
template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
|
||||
class Port {
|
||||
public:
|
||||
int peripheral;
|
||||
PinName pins[N];
|
||||
PinName *ppins[N];
|
||||
|
||||
static const uint32_t pin_count = N;
|
||||
typedef PinMapType PinMap;
|
||||
typedef FunctionType TestFunctionType;
|
||||
|
||||
enum Status { StatusPass, StatusFail, StatusNotTested };
|
||||
Status status;
|
||||
|
||||
Port(): peripheral(NC), status(StatusNotTested)
|
||||
{
|
||||
init_pins();
|
||||
}
|
||||
|
||||
Port(const Port &port)
|
||||
{
|
||||
init_pins();
|
||||
copy_from(port);
|
||||
}
|
||||
|
||||
void init_pins()
|
||||
{
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
pins[i] = NC;
|
||||
ppins[i] = &pins[i];
|
||||
}
|
||||
}
|
||||
|
||||
void copy_from(const Port &port)
|
||||
{
|
||||
peripheral = port.peripheral;
|
||||
status = port.status;
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
pins[i] = port.pins[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
if (peripheral == NC) {
|
||||
return true;
|
||||
}
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
if (pins[i] == NC) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *str()
|
||||
{
|
||||
static char port_str[128];
|
||||
char pin_str[32];
|
||||
sprintf(port_str, "peripheral=(%d) ", peripheral);
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
sprintf(pin_str, "%s=(%s) ", PinMap::pin_type_names[i], FormFactorType::pin_to_string(pins[i]));
|
||||
strcat(port_str, pin_str);
|
||||
}
|
||||
return port_str;
|
||||
}
|
||||
|
||||
friend bool operator==<> (const Port<N, PinMapType, FormFactorType, FunctionType> &port1, const Port<N, PinMapType, FormFactorType, FunctionType> &port2);
|
||||
};
|
||||
|
||||
template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
|
||||
const uint32_t Port<N, PinMapType, FormFactorType, FunctionType>::pin_count;
|
||||
|
||||
template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
|
||||
bool operator== (const Port<N, PinMapType, FormFactorType, FunctionType> &port1, const Port<N, PinMapType, FormFactorType, FunctionType> &port2)
|
||||
{
|
||||
if (port1.peripheral != port2.peripheral) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
if (port1.pins[i] != port2.pins[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience class for use with the above templates
|
||||
*
|
||||
* This class can be passed as a template parameter to all_ports,
|
||||
* all_peripherals or one_peripheral to choose test pins from
|
||||
* the default form factor.
|
||||
*/
|
||||
class DefaultFormFactor {
|
||||
public:
|
||||
static const PinList *pins()
|
||||
{
|
||||
return pinmap_ff_default_pins();
|
||||
}
|
||||
|
||||
static const PinList *restricted_pins()
|
||||
{
|
||||
return pinmap_restricted_pins();
|
||||
}
|
||||
|
||||
static const char *pin_to_string(PinName pin)
|
||||
{
|
||||
return pinmap_ff_default_pin_to_string(pin);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Peripheral port declarations are given below
|
||||
*
|
||||
* Each Port type represents a set of pins used by a peripheral.
|
||||
* The Port typedef is used as a template parameter to the functions
|
||||
* all_ports, all_peripherals and one_peripheral to select the peripheral
|
||||
* pin set to use for testing.
|
||||
*/
|
||||
|
||||
#if DEVICE_SPI
|
||||
#include "spi_api.h"
|
||||
struct SPIMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *SPIMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap(), spi_master_cs_pinmap() };
|
||||
const char *const SPIMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
|
||||
const char *const SPIMaps::name = "SPI";
|
||||
typedef Port<4, SPIMaps, DefaultFormFactor, TF4> SPIPort;
|
||||
|
||||
struct SPINoCSMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *SPINoCSMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap()};
|
||||
const char *const SPINoCSMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK" };
|
||||
const char *const SPINoCSMaps::name = "SPI";
|
||||
typedef Port<3, SPINoCSMaps, DefaultFormFactor, TF3> SPINoCSPort;
|
||||
|
||||
struct SPISlaveMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *SPISlaveMaps::maps[] = { spi_slave_mosi_pinmap(), spi_slave_miso_pinmap(), spi_slave_clk_pinmap(), spi_slave_cs_pinmap() };
|
||||
const char *const SPISlaveMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
|
||||
const char *const SPISlaveMaps::name = "SPISlave";
|
||||
typedef Port<4, SPISlaveMaps, DefaultFormFactor, TF4> SPISlavePort;
|
||||
#endif
|
||||
|
||||
#if DEVICE_I2C
|
||||
#include "i2c_api.h"
|
||||
struct I2CMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *I2CMaps::maps[] = { i2c_master_sda_pinmap(), i2c_master_scl_pinmap() };
|
||||
const char *const I2CMaps::pin_type_names[] = { "SDA", "SCL" };
|
||||
const char *const I2CMaps::name = "I2C";
|
||||
typedef Port<2, I2CMaps, DefaultFormFactor, TF2> I2CPort;
|
||||
#endif
|
||||
|
||||
#if DEVICE_PWMOUT
|
||||
#include "pwmout_api.h"
|
||||
struct PWMMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *PWMMaps::maps[] = { pwmout_pinmap() };
|
||||
const char *const PWMMaps::pin_type_names[] = { "PWM_OUT" };
|
||||
const char *const PWMMaps::name = "PWM";
|
||||
typedef Port<1, PWMMaps, DefaultFormFactor, TF1> PWMPort;
|
||||
#endif
|
||||
|
||||
#if DEVICE_ANALOGIN
|
||||
#include "analogin_api.h"
|
||||
struct AnaloginMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *AnaloginMaps::maps[] = { analogin_pinmap() };
|
||||
const char *const AnaloginMaps::pin_type_names[] = { "ADC_IN" };
|
||||
const char *const AnaloginMaps::name = "ADC";
|
||||
typedef Port<1, AnaloginMaps, DefaultFormFactor, TF1> AnaloginPort;
|
||||
#endif
|
||||
|
||||
#if DEVICE_ANALOGOUT
|
||||
#include "analogout_api.h"
|
||||
struct AnalogoutMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *AnalogoutMaps::maps[] = { analogout_pinmap() };
|
||||
const char *const AnalogoutMaps::pin_type_names[] = { "DAC_OUT" };
|
||||
const char *const AnalogoutMaps::name = "DAC";
|
||||
typedef Port<1, AnalogoutMaps, DefaultFormFactor, TF1> AnalogoutPort;
|
||||
#endif
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
struct UARTMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *UARTMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap(), serial_cts_pinmap(), serial_rts_pinmap() };
|
||||
const char *const UARTMaps::pin_type_names[] = { "TX", "RX", "CLS", "RTS" };
|
||||
const char *const UARTMaps::name = "UART";
|
||||
typedef Port<4, UARTMaps, DefaultFormFactor, TF4> UARTPort;
|
||||
|
||||
struct UARTNoFCMaps {
|
||||
static const PinMap *maps[];
|
||||
static const char *const pin_type_names[];
|
||||
static const char *const name;
|
||||
};
|
||||
const PinMap *UARTNoFCMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap() };
|
||||
const char *const UARTNoFCMaps::pin_type_names[] = { "TX", "RX" };
|
||||
const char *const UARTNoFCMaps::name = "UART-no-FC";
|
||||
typedef Port<2, UARTNoFCMaps, DefaultFormFactor, TF2> UARTNoFCPort;
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue