Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru
Партнеры:
otladka.com.ua - г.Киев

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:1
Поисковых ботовПоисковых ботов:3
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:5
Форум » starterkit.ru » Отладочные платы » SK-iMX53
Проблемы с ECSPI
Maxim
Добавлено 27.01.2014 19:52
0
Сообщение: 1
Maxim
0

Пункты: 722
Регистрация: 14.12.2013
Здравствуйте.
Подключил к плате SPI ADC на 4 канала. После выполнения преобразования из АЦП необходимо забирать 96 бит (4 канала по 24 бита). Передачу данных планировалось сделать с минимальным использованием прерываний, у ECSPI есть аппаратные возможности для организации обмена. В модуле ECSPI у imx53 длину посылки можно выбирать с помощью BURST LENGTH и запускать передачу по сигналу SPI_RDY.
Но на форумах пишут что при длине посылки более 32 бит модуль начинает работать непредсказуемо: https://community.freescale.com/thread/308673.
Кто-нибудь сталкивался с такой проблемой?
Спуститься к концу Подняться к началу
Персональная информация
lexx666
Добавлено 28.01.2014 13:51 Сообщение: 2
lexx666
3.83

Пункты: 11780
Регистрация: 28.07.2011
Пол: Мужчина
Из: Барнаул
Задаете длину слова 16 бит. Вычитываете необходимое количество байт используя стандартный linux драйвер - spidev.
Указанное количество байт вычитывается за раз, за один чип селект (cs).
В чём именно проблема ? Ссылка не работает у меня к сожелению...
Спуститься к концу Подняться к началу
Персональная информация
Jury093
Добавлено 28.01.2014 16:12 Сообщение: 3
Jury093
4.5

Пункты: 54233
Регистрация: 25.05.2009
Пол: Мужчина
Из: Санкт-Петербург
Цитата
В чём именно проблема ? Ссылка не работает у меня к сожелению...

/offtop - надо из приведенного линка убрать точку в конце, типа:
https://community.freescale.com/thread/308673

На любой вопрос есть любой ответ.
Спуститься к концу Подняться к началу
Персональная информация
Maxim
Добавлено 02.03.2014 12:55 Сообщение: 4
Maxim
0

Пункты: 722
Регистрация: 14.12.2013
Для работы с внешним АЦП ads1274 был написан модуль.
АЦП имеет 4 независимых канала, данные передаются по SPI. У АЦП есть выход RDY, когда данные готовы уровень меняется с 1 на 0 и возвращается в 1 после начала чтения по spi или после завершения следующего преобразования. Данные необходимо забирать до завершения следующего преобразования, иначе они теряются. Для чтения используется прерывание по фронту gpio. АЦП выдает данные в виде последовательности из 96 бит (4 канала по 24 бита). Модуль накапливает данные в памяти. Приложение читает их через файл устройства.

1. При минимальной загрузке процессора пропусков в приеме данных нет, но с увеличением нагрузки начинают появляться пропуски. (при запуске qt demo или при выводе файла cat test.txt) Есть ли способ добиться стабильной работы модуля при большой нагрузке на процессор?

2. У spi imx53 есть вход spi rdy. Этот вход может управлять началом передачи данных по spi. При этом длина посылки может быть от 1 до 4095 бит. Но при увеличении длины посылки более 32 бит, отправляется только 32 бита. Работает ли этот режим для посылок длиннее 32 бит?

Код модуля (модуль читает только 32 бита из 96)

Код
#include <linux/kernel.h> /* Для printk() и т.д. */
#include <linux/module.h> /* Эта частичка древней магии, которая оживляет модули */
#include <linux/init.h> /* Определения макросов */
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* put_user */
#include <asm/io.h> /* ioremap_nocache */
#include <linux/ioport.h> /* struct resource */
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#include <linux/cdev.h>

#include "ADS1274.h"

// Ниже мы задаём информацию о модуле, которую можно будет увидеть с помощью Modinfo
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "Author" );
MODULE_DESCRIPTION( "ADC Driver" );
MODULE_SUPPORTED_DEVICE( "ads1274" ); /* /dev/testdevice */

//-------------------------------------------------------------

#define ADC_DRDY_PIN 154
#define ADC_SYNC_PIN 91
#define ADC_TEST_PIN 84

#define SUCCESS 0
#define DEVICE_NAME "ads1274" /* Имя нашего устройства */

#define INPUT_BUFFER_SIZE 21000

// Поддерживаемые нашим устройством операции
static int device_open( struct inode *, struct file * );
static int device_release( struct inode *, struct file * );
static ssize_t device_read( struct file *, char *, size_t, loff_t * );
static ssize_t device_write( struct file *, const char *, size_t, loff_t * );

// Глобальные переменные, объявлены как static, воизбежание конфликтов имен.
static dev_t first; // Global variable for the first device number
static struct cdev c_dev; // Global variable for the character device structure
static struct class *cl; // Global variable for the device class


//static int major_number; /* Старший номер устройства нашего драйвера */
static int is_device_open = 0; /* Используется ли девайс ? */

static int status_reg;
//static int test_data_cnt = 0;
//int testVrVar;

static int region_size = 256;

static void *ccm_base;
static void *pwm1_base;
static void *ecspi1_base;




struct
{
int dataA[(INPUT_BUFFER_SIZE+3)];
int dataB[(INPUT_BUFFER_SIZE+3)];
unsigned char busy_buff;
int start;
int end;
} inputBuffer;

// Прописываем обработчики операций на устройством
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};

static irqreturn_t ads1274_interrupt(int irq, void *dev_id)
{
status_reg = *(int*)(ecspi1_base+ECSPI_STATREG);
status_reg &= 0x00000008;

while(status_reg == 0x08)
{
status_reg = *(int*)(ecspi1_base+ECSPI_STATREG);
status_reg &= 0x00000008;

if (status_reg == 0x00000008)
{
if (inputBuffer.busy_buff == 1)
{
inputBuffer.dataB[inputBuffer.end] = *(int*)(ecspi1_base+ECSPI_RXDATA);

inputBuffer.end++;
if (inputBuffer.end >= INPUT_BUFFER_SIZE)
{
inputBuffer.busy_buff = 0;
inputBuffer.end = 0;
}
}
else
{
inputBuffer.dataA[inputBuffer.end] = *(int*)(ecspi1_base+ECSPI_RXDATA);
inputBuffer.end++;

if (inputBuffer.end >= INPUT_BUFFER_SIZE)
{
inputBuffer.busy_buff = 1;
inputBuffer.end = 0;
}
}
}
}

*(int*)(ecspi1_base+ECSPI_TXDATA) = 0x00000000;

return IRQ_HANDLED;
}

static void ResetInputBuffer(void)
{
inputBuffer.busy_buff = 0;
inputBuffer.start=0;
inputBuffer.end=0;
}

static int gpio_irq_init(void)
{
int ret;

ret = gpio_request(ADC_DRDY_PIN, "gpio154"); //GPIO_5_26
if (ret < 0)
{
printk("ADS1274 driver: can't get GPIO pin: %d\n", ADC_DRDY_PIN);
return ret;
}

printk("GPIO pin: %d\n", ADC_DRDY_PIN);

gpio_direction_input(ADC_DRDY_PIN);
set_irq_type(gpio_to_irq(ADC_DRDY_PIN), IRQ_TYPE_EDGE_FALLING);

ret = request_irq(gpio_to_irq(ADC_DRDY_PIN), ads1274_interrupt, IRQF_TRIGGER_FALLING, "adc_drdy_int", NULL);
if (ret < 0)
{
printk("ADS1274 driver: IRQ request failed: %d\n", ret);
return ret;
}

return SUCCESS;
}

// Функция загрузки модуля. Входная точка. Можем считать что это наш main()
static int __init ads1274_init( void )
{
int gpio3_ret;
unsigned int wait_del;
int gpio_test_ret;
int gpio_int_status;

struct resource *res;

printk( KERN_ALERT "ADS1274 driver loaded!\n" );

ResetInputBuffer();

res = request_mem_region(CCM_BASE, region_size, "ccm");
ccm_base = ioremap_nocache(CCM_BASE, region_size);

res = request_mem_region(PWM1_BASE, region_size, "pwm1");
pwm1_base = ioremap_nocache(PWM1_BASE, region_size);

res = request_mem_region(ECSPI1_BASE, region_size, "ecspi1");
ecspi1_base = ioremap_nocache(ECSPI1_BASE, region_size);

*(int*)(ccm_base+CCM_CCGR2) |= 0xC00; // ipg_clk
*(int*)(ccm_base+CCM_CCGR4) |= 0x3C0000;

*(int*)(pwm1_base+PWM_PWMCR) = 0; // Disable PWM
*(int*)(pwm1_base+PWM_PWMCR) = 0x3C10000;
*(int*)(pwm1_base+PWM_PWMSR) = 0;
*(int*)(pwm1_base+PWM_PWMIR) = 0;
*(int*)(pwm1_base+PWM_PWMSAR) = 2;
*(int*)(pwm1_base+PWM_PWMPR) = 3;
*(int*)(pwm1_base+PWM_PWMCR) |= 1; // Enable PWM

*(int*)(ecspi1_base+ECSPI_CONREG) = 0; /* Disable ECSPI */
*(int*)(ecspi1_base+ECSPI_CONREG) = 0x017010F8;
*(int*)(ecspi1_base+ECSPI_CONFIGREG) = 0x00FF0FFF;
*(int*)(ecspi1_base+ECSPI_INTREG) = 0; /* Rx Int Enabled */
*(int*)(ecspi1_base+ECSPI_DMAREG) = 0; /* DMA Disabled, 45 elements in RxFIFO */
*(int*)(ecspi1_base+ECSPI_PERIODREG) = 0x00000000; /* Delay Disabled */
*(int*)(ecspi1_base+ECSPI_TESTREG) = 0; /* Test Disabled */
*(int*)(ecspi1_base+ECSPI_CONREG) |= 1; /* Enable ECSPI */

gpio_test_ret = gpio_request(ADC_TEST_PIN, "gpio84"); //GPIO_3_20

if (gpio_test_ret < 0)
{
printk("TSTDRV: can't get GPIO TEST pin: %d\n", ADC_TEST_PIN);
return gpio_test_ret;
}

printk("GPIO TEST PIN: %d\n", ADC_TEST_PIN);

gpio_direction_output(ADC_TEST_PIN,0);
gpio_set_value(ADC_TEST_PIN, 1);

gpio3_ret = gpio_request(ADC_SYNC_PIN, "gpio91"); //ADC_SYNC - GPIO_3_27

if (gpio3_ret < 0)
{
printk("TSTDRV: can't get GPIO RDY pin: %d\n", ADC_SYNC_PIN);
return gpio3_ret;
}

printk("GPIO RDY PIN: %d\n", ADC_SYNC_PIN);

gpio_direction_output(ADC_SYNC_PIN,0);

for (wait_del = 0; wait_del < 2000; wait_del++); /* Wait ADC Reset */

gpio_set_value(ADC_SYNC_PIN, 1);

// int alloc_chrdev_region(dev_t *first, unsigned int firstminor, unsigned int cnt, char *name);
// динамически определяется свободный старший номер и регистрируется число cnt(1) среди номеров файлов устройств, начинающиеся с <the free major, firstminor>,
// с заданным именем файла name.

if (alloc_chrdev_region(&first, 0, 1, "adc1274driver") < 0)
{
return -1;
}

// Класс устройства создается следующим образом:
// struct class *cl = class_create(THIS_MODULE, "<device class name>");

if ((cl = class_create(THIS_MODULE, "adc")) == NULL)
{
unregister_chrdev_region(first, 1);
return -1;
}

// Затем в этот класс информация об устройстве (<major, minor>) заносится следующим образом:
// device_create(cl, NULL, first, NULL, "<device name format>", ...);

if (device_create(cl, NULL, first, NULL, "ads1274") == NULL)
{
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}

// занесем нужные нам файловые операции (my_open, my_close, my_read, my_write, …) в структуру,
// описывающую файловые операции (struct file_operations pugs_fops)
// и ею инициализируем структуру, описывающую символьное устройство (struct cdev c_dev);
// используем для этого обращение cdev_init().

cdev_init(&c_dev, &fops);

// Затем передадим эту структуру в VFS с помощью вызова cdev_add()

if (cdev_add(&c_dev, first, 1) == -1)
{
device_destroy(cl, first);
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}

printk( "ADS1274 module is loaded!\n" );

gpio_int_status = gpio_irq_init();

return gpio_int_status;
}

// Функция выгрузки модуля
static void __exit ads1274_exit( void )
{
// Освобождаем устройство
free_irq(gpio_to_irq(ADC_DRDY_PIN), NULL);



cdev_del(&c_dev);
device_destroy(cl, first);
class_destroy(cl);
unregister_chrdev_region(first, 1);

release_mem_region(CCM_BASE, region_size);
release_mem_region(PWM1_BASE, region_size);
release_mem_region(ECSPI1_BASE, region_size);

iounmap(ccm_base);
iounmap(pwm1_base);

iounmap(ecspi1_base);

printk( KERN_ALERT "ADS1274 module is unloaded!\n" );
}

// Указываем наши функции загрузки и выгрузки
module_init( ads1274_init );
module_exit( ads1274_exit );

static int device_open( struct inode *inode, struct file *file )
{
if ( is_device_open ) return -EBUSY;

is_device_open++;

return SUCCESS;
}

static int device_release( struct inode *inode, struct file *file )
{
is_device_open--;
return SUCCESS;
}

static ssize_t device_write( struct file *filp, const char *buff, size_t len, loff_t * off )
{
printk( "Sorry, this operation isn't supported.\n" );
return -EINVAL;
}

static ssize_t device_read( struct file *filp, /* include/linux/fs.h */
char *buffer, /* buffer */
size_t length, /* buffer length */
loff_t * offset )
{
int byte_read = 0;
int rx;
int rx1;
char vr_data1;

while (length)
{
if (inputBuffer.busy_buff == 0)
{
rx = inputBuffer.dataB[byte_read];
}
else
{
rx = inputBuffer.dataA[byte_read];
}

if (length > 0)
{
vr_data1 = rx;
put_user( vr_data1, buffer++ );

length--;
}

if (length > 0)
{
rx1 = rx >> 8;
vr_data1 = rx1;
put_user( vr_data1, buffer++ );

length--;
}

if (length > 0)
{
rx1 = rx >> 16;
vr_data1 = rx1;
put_user( vr_data1, buffer++ );

length--;
}

if (length > 0)
{
rx1 = rx >> 24;
vr_data1 = rx1;
put_user( vr_data1, buffer++ );

length--;
}

byte_read++;
if (byte_read > INPUT_BUFFER_SIZE) break;
}

return (4*byte_read);
}
Спуститься к концу Подняться к началу
Персональная информация
Jury093
Добавлено 02.03.2014 13:22 Сообщение: 5
Jury093
4.5

Пункты: 54233
Регистрация: 25.05.2009
Пол: Мужчина
Из: Санкт-Петербург
Цитата
Но при увеличении длины посылки более 32 бит, отправляется только 32 бита. Работает ли этот режим для посылок длиннее 32 бит?

в сообщение за январь приведена ссылка на форум, откуда растет еще одна ссылка, где ребята с осциллографом показали Silicon bug espi imx53 как раз для вариантов 32+ бита..

что показывает осциллограф в вашем случае?

На любой вопрос есть любой ответ.
Спуститься к концу Подняться к началу
Персональная информация
buletz
Добавлено 03.03.2014 14:00 Сообщение: 6
buletz
3

Пункты: 5920
Регистрация: 16.11.2011
Пол: Мужчина
В мануале на imx53 есть такие строки:

ECSPIx_CONREG field descriptions
....
31–20 BURST LENGTH In slave mode, only when SS_CTL is cleared, this field will take effect in the transfer.


При этом для регистра ECSPIx_CONFIGREG, в котором содержится SS_CTL указано следующее:
11–8 SS CTL ....1 In slave mode - an SPI burst is completed by the Chip Select (SS) signal edges. (SSPOL = 0: rising edge; SSPOL = 1: falling edge) The RXFIFO is advanced whenever a Chip Select (SS) signal edge is detected or the shift register contains 32-bits of valid data.


Может быть попробовать SS_CTL выставить в ноль?
Спуститься к концу Подняться к началу
Персональная информация
Maxim
Добавлено 09.03.2014 17:06 Сообщение: 7
Maxim
0

Пункты: 722
Регистрация: 14.12.2013
imx53 - master, ads1274 - slave
CONREG = 0x00F100F8 - на осциллографе 16 бит
CONREG = 0x01F100F8 - на осциллографе 32 бита
CONREG = 0x05F100F8 - на осциллографе только 32 бита

SS_CTL are ignored if the SMC bit is set. Пробовал SMC = 0, SS_CTL = 0 и 1. В обоих случаях передается только 32 бита.

Какие есть варианты решения проблемы с пропусками прерываний? Есть ли настройки в ядре или проблему можно решить только с помощью железа (складывать данные в буфер с помощью железки, а затем передавать их в linux)?
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Отладочные платы » SK-iMX53