mirror of https://github.com/ARMmbed/mbed-os.git
295 lines
10 KiB
C++
295 lines
10 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2018 ARM Limited
|
|
*
|
|
* 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 "utest/utest.h"
|
|
#include "unity/unity.h"
|
|
#include "greentea-client/test_env.h"
|
|
#include "mbed.h"
|
|
#include "math.h"
|
|
|
|
#define THREAD_STACK_SIZE 1024
|
|
|
|
#if !DEVICE_SAI
|
|
#error [NOT_SUPPORTED] SAI not supported for this target
|
|
#endif
|
|
|
|
using namespace utest::v1;
|
|
|
|
/* Since boards on CI do not have wire SAI loop-back connection, some of the functional
|
|
* tests can not be executed.
|
|
* If you want to fully test SAI support please connect pins as follows:
|
|
* - SAI_A_SD <--> SAI_B_SD
|
|
* - SAI_A_BCLK <--> SAI_B_BCLK
|
|
* - SAI_A_WCLK <--> SAI_B_WCLK
|
|
* and enable loop-back tests by setting LOOPBACK_CONNECTION to true.
|
|
*/
|
|
#define LOOPBACK_CONNECTION (false)
|
|
|
|
#define BUFFER_SIZE 100
|
|
|
|
typedef enum
|
|
{
|
|
LOOPBACK_TEST_OK, LOOPBACK_TEST_SKIP, LOOPBACK_TEST_FAILURE
|
|
} loopback_test_tatus_t;
|
|
|
|
static uint32_t transmit_buffer[BUFFER_SIZE];
|
|
static uint32_t receive_buffer[BUFFER_SIZE];
|
|
|
|
/* Auxiliary function which sets the specified buffer using specified pattern. */
|
|
static void set_buffer(void * buffer, uint32_t size, char pattern)
|
|
{
|
|
char* p_byte = (char*) buffer;
|
|
|
|
while (size--) {
|
|
*p_byte = pattern;
|
|
p_byte++;
|
|
}
|
|
}
|
|
|
|
/* Auxiliary function which compares two buffers and returns true if both are the same. */
|
|
static bool compare_buffers(const void *buffer1, const void *buffer2, uint32_t size)
|
|
{
|
|
const unsigned char *p1 = (const unsigned char *) buffer1;
|
|
const unsigned char *p2 = (const unsigned char *) buffer2;
|
|
while (size--) {
|
|
if (*p1 != *p2) {
|
|
return false;
|
|
} else {
|
|
p1++;
|
|
p2++;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Number of formats which must be supported by SAI device.
|
|
* This variable defines number of obligate formats in test_sai_formats array. */
|
|
const uint32_t required_formats_count = 5;
|
|
|
|
/* Array of tested formats. */
|
|
static sai_format_t test_sai_formats[] = {
|
|
// Formats which are requested for all SAI devices
|
|
sai_mode_i2s16,
|
|
sai_mode_i2s16w32,
|
|
sai_mode_i2s32,
|
|
sai_mode_pcm16l,
|
|
sai_mode_pcm16s,
|
|
// Other formats
|
|
|
|
};
|
|
|
|
/* Test that SAI class is able to communicate in loop-back mode.
|
|
*
|
|
* Given is SAI Class and SAI loop-back connection.
|
|
* When SAI object is configured as transmitter with the specified format and
|
|
* another SAI object is configured as receiver with the same format used.
|
|
* Then transmitter can successfully transmit samples to the receiver.
|
|
*/
|
|
void SAI_transmission_test()
|
|
{
|
|
loopback_test_tatus_t status;
|
|
|
|
if (!LOOPBACK_CONNECTION) {
|
|
TEST_IGNORE_MESSAGE("NO LOOPBACK CONNECTION - TEST SKIPPED!");
|
|
return;
|
|
}
|
|
|
|
char message[50];
|
|
|
|
for (uint32_t f_idx = 0; f_idx < (sizeof(test_sai_formats) / sizeof(sai_format_t)); f_idx++) {
|
|
|
|
SAI sai_transmitter(SAI_A_MCLK, // mclk
|
|
SAI_A_BCLK, // bclk
|
|
SAI_A_WCLK, // wclk
|
|
SAI_A_SD, // SD
|
|
&test_sai_formats[f_idx], // format
|
|
false, // is input
|
|
0, // master clock
|
|
false // internal mclk
|
|
);
|
|
|
|
SAI sai_receiver(SAI_B_MCLK, // mclk
|
|
SAI_B_BCLK, // bclk
|
|
SAI_B_WCLK, // wclk
|
|
SAI_B_SD, // SD
|
|
&test_sai_formats[f_idx], // format
|
|
true, // is input
|
|
0, // master clock
|
|
false // internal mclk
|
|
);
|
|
|
|
// we should check init status before the actual test - for now there is no such option
|
|
sai_result_t transmitter_init_status = SAI_RESULT_OK;
|
|
sai_result_t receiver_init_status = SAI_RESULT_OK;
|
|
|
|
/* Continue test only if SAI device has been successfully configured. */
|
|
if (transmitter_init_status == SAI_RESULT_OK && receiver_init_status == SAI_RESULT_OK) {
|
|
|
|
const uint32_t data_mask = ((1 << test_sai_formats[f_idx].data_length) - 1);
|
|
|
|
/* Set to unexpected. */
|
|
set_buffer(receive_buffer, sizeof(receive_buffer), 0xFF);
|
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
|
transmit_buffer[i] = data_mask / 100 * i;
|
|
}
|
|
|
|
uint32_t write_cnt = 0;
|
|
uint32_t read_cnt = 0;
|
|
uint32_t sample;
|
|
|
|
/* Send samples and read them back. */
|
|
while (1) {
|
|
if (write_cnt < BUFFER_SIZE) {
|
|
sample = transmit_buffer[write_cnt];
|
|
if (sai_transmitter.xfer(&sample) == true) {
|
|
write_cnt++;
|
|
}
|
|
}
|
|
|
|
if (sai_receiver.xfer(&sample) == true) {
|
|
receive_buffer[read_cnt] = sample;
|
|
read_cnt++;
|
|
}
|
|
|
|
if (read_cnt == BUFFER_SIZE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (compare_buffers(transmit_buffer, receive_buffer, BUFFER_SIZE) == true) {
|
|
status = LOOPBACK_TEST_OK;
|
|
} else {
|
|
status = LOOPBACK_TEST_FAILURE;
|
|
}
|
|
} else {
|
|
status = LOOPBACK_TEST_SKIP;
|
|
}
|
|
|
|
/* First `required_formats_count` formats are obligate, so we expect that
|
|
* communication tests passes. Others formats may be supported, so test can pass or be skipped.
|
|
*/
|
|
sprintf(message, "format idx: %lu", f_idx);
|
|
if (f_idx < required_formats_count) {
|
|
TEST_ASSERT_EQUAL_MESSAGE(LOOPBACK_TEST_OK, status, message);
|
|
} else {
|
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(LOOPBACK_TEST_FAILURE, status, message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Test that SAITransmitter class is able to send samples in loop-back mode.
|
|
* Test that SAIReceiver class is able to receive samples in loop-back mode.
|
|
*
|
|
* Given are SAITransmitter and SAIReceiver Classes and SAI loop-back connection.
|
|
* When SAI object is configured as transmitter with the specified format and
|
|
* another SAI object is configured as receiver with the same format used.
|
|
* Then transmitter can successfully transmit samples to the receiver.
|
|
*/
|
|
void SAITransmitter_SAIReceiver_transmission_test()
|
|
{
|
|
loopback_test_tatus_t status;
|
|
|
|
if (!LOOPBACK_CONNECTION) {
|
|
TEST_IGNORE_MESSAGE("NO LOOPBACK CONNECTION - TEST SKIPPED!");
|
|
return;
|
|
}
|
|
|
|
char message[50];
|
|
|
|
for (uint32_t f_idx = 0; f_idx < (sizeof(test_sai_formats) / sizeof(sai_format_t)); f_idx++) {
|
|
|
|
SAITransmitter sai_transmitter(SAI_A_MCLK, SAI_A_BCLK, SAI_A_WCLK, SAI_A_SD, &test_sai_formats[f_idx]);
|
|
SAIReceiver sai_receiver(SAI_B_MCLK, SAI_B_BCLK, SAI_B_WCLK, SAI_B_SD, &test_sai_formats[f_idx]);
|
|
|
|
// we should check init status before the actual test - for now there is no such option
|
|
sai_result_t transmitter_init_status = SAI_RESULT_OK;
|
|
sai_result_t receiver_init_status = SAI_RESULT_OK;
|
|
|
|
/* Continue test only if SAI device has been successfully configured. */
|
|
if (transmitter_init_status == SAI_RESULT_OK && receiver_init_status == SAI_RESULT_OK) {
|
|
|
|
const uint32_t data_mask = ((1 << test_sai_formats[f_idx].data_length) - 1);
|
|
|
|
/* Set to unexpected. */
|
|
set_buffer(receive_buffer, sizeof(receive_buffer), 0xFF);
|
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
|
transmit_buffer[i] = data_mask / 100 * i;
|
|
}
|
|
|
|
uint32_t write_cnt = 0;
|
|
uint32_t read_cnt = 0;
|
|
uint32_t sample;
|
|
|
|
/* Send samples and read them back. */
|
|
while (1) {
|
|
if (write_cnt < BUFFER_SIZE) {
|
|
sample = transmit_buffer[write_cnt];
|
|
if (sai_transmitter.send(sample) == true) {
|
|
write_cnt++;
|
|
}
|
|
}
|
|
|
|
if (sai_receiver.receive(&sample) == true) {
|
|
receive_buffer[read_cnt] = sample;
|
|
read_cnt++;
|
|
}
|
|
|
|
if (read_cnt == BUFFER_SIZE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (compare_buffers(transmit_buffer, receive_buffer, BUFFER_SIZE) == true) {
|
|
status = LOOPBACK_TEST_OK;
|
|
} else {
|
|
status = LOOPBACK_TEST_FAILURE;
|
|
}
|
|
} else {
|
|
status = LOOPBACK_TEST_SKIP;
|
|
}
|
|
|
|
/* First `required_formats_count` formats are obligate, so we expect that
|
|
* communication tests passes. Others formats may be supported, so test can pass or be skipped.
|
|
*/
|
|
sprintf(message, "format idx: %lu", f_idx);
|
|
if (f_idx < required_formats_count) {
|
|
TEST_ASSERT_EQUAL_MESSAGE(LOOPBACK_TEST_OK, status, message);
|
|
} else {
|
|
TEST_ASSERT_NOT_EQUAL_MESSAGE(LOOPBACK_TEST_FAILURE, status, message);
|
|
}
|
|
}
|
|
}
|
|
|
|
Case cases[] = {
|
|
Case("SAI - loopback communication test.", SAI_transmission_test),
|
|
Case("SAITransmitter/SAIReceiver - loopback communication test.", SAITransmitter_SAIReceiver_transmission_test),
|
|
};
|
|
|
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
|
{
|
|
GREENTEA_SETUP(40, "default_auto");
|
|
return greentea_test_setup_handler(number_of_cases);
|
|
}
|
|
|
|
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
|
|
|
int main()
|
|
{
|
|
Harness::run(specification);
|
|
}
|