This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] Linux/OMAP-L138:从 Linux 应用程序中读取 SPI 接口速度慢

Guru**** 2589245 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/591182/linux-omap-l138-spi-interface-reads-out-slow-from-linux-application

器件型号:OMAP-L138

工具/软件:Linux

我们在 SPI 总线上有三个器件。  主器件是 OMAP/ARM 处理器、以2MHz 的频率驱动时钟(这已通过示波器进行验证)。  两个从器件位于 OMAP 的芯片选择2和3上。  正在成功发送和接收数据。  问题是、我们接收数据的速率比它应该慢一个数量级。  我们不是以3584Hz (理想频率)读取数据、而是以177Hz 的频率读取数据。  当我们不发送/接收数据时、我已验证轮询环路本身以3584Hz 的频率运行。  当我打开函数从器件中读取数据时、每个器件需要~5.7毫秒的时间来轮询和接收完整的数据流。  请求数据大小为32字节、任一器件的最大响应大小为32字节。  因此、总往返轮询/响应为64字节或512位。  

我们不使用 DMA 的部分原因是有关如何使用 DMA 的文档太差。  如果存在阻塞条件、如本例所示、使用 SPI 读取数据、这可能是一种解决方案。

对问题可能有什么想法?  

谢谢、

Erik Jones

支持信息:

--------------------------------------------

处理器:SOMOMAPL138-10-1602QHIR-B

编译器包:CodeSourcery Sourcery G++ Lite  4.3.3版(Sourcery G++ Lite 2009q1-203)  

RootFS:Arago  

SPI 应用代码:


bool SPIController::sendData (spiDevices spiDevice、SPIRequestBase *命令){
int spiDev = open (spiDeviceTable[spiDevice].deviceName.c_str()、O_RDWR);
INT MODE = SPI_MODE_0;
int res = 0;
struct spi_io_transfer spiControl;
memset (&spiControl、0、sizeof (spiControl));

setCS (spiDevice、true);

char * xmitBuffer = new char [spiDeviceTable[spiDevice].max_packet_length];
memset (xmitBuffer、0、spiDeviceTable[spiDevice].max_packet_length);
memcpy (xmitBuffer、Command->getPacketbuffer ()、spiDeviceTable[spiDevice].max_packet_length);

char * recvBuffer = new char [spiDeviceTable[spiDevice].max_packet_length];
memset (recvBuffer、0、spiDeviceTable[spiDevice].max_packet_length);

RES = ioctl (spiDev、SPI_IOC_WR_MODE、&MODE);

spiControl.TX_Buf =(无符号长整型) xmitBuffer;
spiControl.Rx_Buf =(无符号长整型) recvBuffer;
spiControl.len = spiDeviceTable[spiDevice].max_packet_length;
spiControl.speed_Hz = SPIController:spiClock;
spiControl.cs_change = 0;
spiControl.bits_per_word = 8;
spiControl.delay_usecs = 0;

if (spiDevice = PIM_datalogger)
xmitBuffer[spiDeviceTable[spiDevice].max_packet_length-1]= 0xAA;

RES = ioctl (spiDev、SPI_IOC_MESSAGE (1)、&spiControl);

//临时检测
if (spiDevice =PIM_platform &&*(recvBuffer + spiDeviceTable[spiDevice].max_packet_length - 1)=0){
memMove (recvBuffer+1、recvBuffer、spiDeviceTable[spiDevice].max_packet_length-1);

*recvBuffer=0;

//Sign extension
if ((*(recvBuffer+1)& 0x80)>0)
* recvBuffer = 0xFF;


SPIResponseBase * pr = SPIResponseBase::Dispatch (recvBuffer、spiDevice、spiDeviceTable[spiDevice].max_packet_length);

SPIController::当前遥测.U16_DatLog_ActiveFile_Index_HB = DataLogController::getFileNum()>> 16;
SPIController::当前遥测.U16_DatLog_ActiveFile_Index_LB = DataLogController:getFileNum()& 0xFF;
SPIController::currentTelemety.u8_ConfigFile_ID = NetworkServerController::getConfigFileID();
SPIController::currentTelemety.u8_mode = NetworkServerController::getCurrentMode();
SPIController::currentTelemetice.u32_counter++;

SPIController::currentTelemetry =*pr;

Close (spidDev);

setCS (spiDevice、false);

删除[] xmitBuffer;
删除[] recvBuffer;

删除 pr;

返回 true;



bool SPIController::setCS (spiDevices spiDevice、bool enable){
std::字符串 devicePin、enableStr;

enableStr =启用? "0":"1";

switch (spiDevice){
案例 PIM_PLANTANT:
devicePin = SPIController:SPI_CS2;
中断;
案例 PIM_DATALOGGER:
devicePin = SPI 控制器::SPI_CS3;
中断;


std::string setval_str ="/sys/class/gpio/gpio + devicePin +"/value";
ofstream setvalgpio (setval_str.c_str ());//打开 GPIO 的值文件
if (setvalgpio < 0){
COUT <<"操作失败:无法设置 GPIO"<<devicePin <<"."<endl;
返回 false;


setvalgpio << enableStr;//write value to value file
setvalgpio.close();//关闭值文件
返回 true;

内核:来自 ti-dvsdk-omap138-EVM 4.02.0.6 - 2.6.33-RC4-psp03.2.0.14

芯片选择2和3上的 SPI 器件。 通过硬编码 SPI 驱动器修改将时钟设置为2MHz。 在 mach-Davinci/board-da850-EVM.c 中:

静态结构 SPI_board_info da850_SPI_board_info[]={
[0]={
modalias ="m25p80"、
.platform_data =&spi_flash_data、
.mode = SPI_MODE_0、
.max_speed_Hz = 2000000、/* 3V 时的最大采样率*
.bus_num = 1、
.chip_select = 0、
}、


/*可编程隔离安装*/
[1]={
modalias ="spidev"、
.mode = SPI_MODE_0、
.max_speed_Hz = 2000000、/* 3V 时的最大采样率*
.bus_num = 1、
.chip_select = 2、
}、
[2]={

modalias ="spidev"、
.mode = SPI_MODE_0、
.max_speed_Hz = 2000000、/* 3V 时的最大采样率*
.bus_num = 1、
.chip_select = 3、
}、

};

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!

    尝试在 drivers/SPI-Davinci.c 中分配 DMA TX 和 Rx 通道 目前这些设置为:
    resource_size_t dma_rx_chan = spi_no_resource;
    resource_size_tdma_tx_chan = spi_no_resource;

    SPI DMA Rx 和 TX 通道映射在 arch/arm/mach-Davinci/devices/da8xx.c 中定义

    有关如何使用 DMA API 的更多信息、请参见 Documentation/dma-api.txt、Documentation/dma-api-HOWTO .txt、Documentation/dma-attributes.txt、Documentation/dma-buf-sharing.txt 和 Documentation/dmaengine.txt

    此致、
    Yordan
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Yordan、您好!

    感谢您的建议。  您是否认为无需重新编译内核即可启用 DMA?  我们的装置当前位于空间站上、我们不确定是否可以更新内核。  在我们的 SOM 配置中、引导管理器(U-boot)用于下载和存储内核映像。  我认为有一种方法可以从 Linux 更新内核的闪存副本、但我们以前没有这样做。  

    感谢你能抽出时间、

    Erik

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Erik、

    有一些选项:
    1.尝试创建用户空间 DMA 驱动程序,并在 SPI 应用程序中使用通道。 有关用户空间 DMA 映射的一些文档可在以下社区讨论中找到:
    stackoverflow.com/.../linux-kernel-device-driver-to-dma-from-a-device-into-user-space-memory
    forums.xilinx.com/.../Linux 来自用户 Space-public.pdf 的 DMA
    github.com/.../udmabuf

    2.您可以在启用 DMA 的情况下从内核源交叉编译 SPI 驱动程序,然后将生成的.ko 文件传输到主板,rmmod 旧的 SPI 驱动程序并输入新的驱动程序(启用 DMA)。

    这可能是一项棘手的任务、因为我想、您无法承担试错... 因此、您可能需要测试现场电路板上选择的任何方法、一旦验证其工作正常、您就可以将其传输到空间站上的装置上。

    此致、
    Yordan