SPI是我最常用的接口之一,连接管脚仅为4根;在常见的芯片间通信方式中,速度远优于UART、I2C等其他接口。STM32的SPI口的同步时钟最快可到PCLK的二分之一,单个字节或字的通信时间都在us以下,因此大多数情况下我们会使用查询法控制SPI口的传输。但对于大量且连续的通信,再使用查询法就显得有些浪费CPU的时间,DMA控制SPI的读写显然成为一种不错的选择。

为DMA控制SPI批量数据读写的功能,参照官方代码编写的DMA控制SPI口在主/从两种模式下,读写数据的的代码,供各位网友直接使用或批评指正。先直接上我得到结论:

1、运用STM32的SPI口的DMA的功能,能够提升STM32与外设之间通信的速率和实时性。

2、但在STM32的SPI的主机模式下,DMA控制器无法自动产生片选CS信号,只能与无需同步CS信号的外设器件通信。为产生同步的CS信号,只能由软件控制SPI逐字发送,而DMA仅用于接收SPI数据,这样做的效率和不使用DMA时一样。

3、主模式下,软件控制片选CS信号和SPI读写时,存在至少50%的时间空隙,降低了其SPI通信的效率

4、STM32的SPI主机模式下,无法只使用DMA接收,而不发送。原因是没有触发SPI的DMA接收的信号。但SPI的发送可以是软件控制的逐字发送,也可以是DMA控制的连续发送。

5、STM32的SPI若要使用DMA方式,最合适的是让STM32工作在SPI的从模式,由外部主机(如FPGA)来控制通信的实时性和高速性。

以下原创内容欢迎网友转载,但请注明出处: https://www.cnblogs.com/helesheng

一、STM32做SPI主机(Master)时的DMA传输

STM32做SPI主机进行DMA通信时,尤其需要注意的是:不能单独使用SPI接收数据DMA,一定要配合SPI发送数据,DMA接收数据通道才能收到数据。道理很简单:STM32做主机时,如果不主动发送数据将无法产生时钟和片选等信号,亦无法在传输完成后触发DMA接收数据。但在使用时,这一点非常容易被忽视,从而造成DMA接收SPI数据通道DMA1CH2和DMACH4“不工作”。

图1、STM32 DMA1各通道功能

具体来说,使用SPI口的DMA接收功能有两种配置方法:

1、SPI口的接收和发送各使用一个DMA通道

这样做最符合DMA控制大量数据连续发送和接收的设计初衷,此种情况下的SPI口和两个DMA通道的配置分别如下:

  1. 1 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );
  2. 2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;//PA5 6 7是SPI1的SCK MIOS MOSI
  3. 3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  4. 4 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  5. 5 GPIO_Init(GPIOA, &GPIO_InitStructure);
  6. 6 GPIO_SetBits(GPIOA , GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //将其置位
  7. 7 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  8. 8 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
  9. 9 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收8位帧结构
  10. 10 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //空闲时时钟为低电平
  11. 11 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿
  12. 12 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //SPI_NSS_Hard; ////NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  13. 13 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //定义波特率预分频的值
  14. 14 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  15. 15 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
  16. 16 SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
  17. 17 SPI_Cmd(SPI1, ENABLE); //使能SPI1外设

SPI的配置

  1. 1 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
  2. 2 ///////以下配置DMA CH2用于接收SPI的DMA通道/////
  3. 3 DMA_DeInit(DMA1_Channel2); //将DMA的通道1寄存器重设为缺省值
  4. 4 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); //DMA外设基地址
  5. 5 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)spi_rx_buff; //DMA内存基地址
  6. 6 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取数据到内存
  7. 7 DMA_InitStructure.DMA_BufferSize = num; //DMA通道的DMA缓存的大小
  8. 8 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
  9. 9 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
  10. 10 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
  11. 11 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
  12. 12 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式
  13. 13 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有中优先级
  14. 14 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
  15. 15 DMA_Init(DMA1_Channel2, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
  16. 16 ///////以下配置DMA的SPI发送通道///////////
  17. 17 DMA_DeInit(DMA1_Channel3);
  18. 18 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); //设置接收外设(0x4001300C) 地址(源地址)
  19. 19 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_tx_buff; //设置 SRAM 存储地址(源地址)
  20. 20 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //传输方向 内存-外设
  21. 21 DMA_InitStructure.DMA_BufferSize = num; //设置 SPI1 接收长度
  22. 22 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址增量(不变)
  23. 23 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址增量(变化)
  24. 24 DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_HalfWord; //外设传输宽度(字节)
  25. 25 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存传输宽度(字节)
  26. 26 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //传输方式,一次传输完停止,不重新加载
  27. 27 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA优先级
  28. 28 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //内存到内存方式禁止
  29. 29 DMA_Init(DMA1_Channel3, &DMA_InitStructure);

收发两个DMA通道的配置

主程序中收发控制程序如下:

  1. 1 SPIx_Init();//SPI初始化
  2. 2 DMA_Config(256);//配置DMA对应的两个通道,数据深度设为256
  3. 3 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE);
  4. 4 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Tx , ENABLE);
  5. 5 while(1)
  6. 6 {
  7. 7 DMA_SetCurrDataCounter(DMA1_Channel2,256);//必须在每次启动DMA之前设置
  8. 8 DMA_SetCurrDataCounter(DMA1_Channel3,256);//必须在每次启动DMA之前设置
  9. 9 DMA_Cmd(DMA1_Channel2, ENABLE); //使能DMA所指示的通道
  10. 10 DMA_Cmd(DMA1_Channel3, ENABLE); //使能DMA所指示的通道
  11. 11 while(1)
  12. 12 {
  13. 13 if(DMA_GetFlagStatus(DMA1_FLAG_TC2) != RESET) //判断通道2传输完成
  14. 14 {
  15. 15 DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志
  16. 16 break;
  17. 17 }
  18. 18 }
  19. 19 DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA
  20. 20 DMA_Cmd(DMA1_Channel3, DISABLE);//禁止DMA
  21. 21 delay_ms(1);
  22. 22 }

SPI主机DMA使用流程

这里我没有使用DMA中断,为的是验证代码的简单易懂;在实际使用时,建议读者使用中断以提高数据读写效率。另外,代码中值得注意的地方有:

1、    使用DMA传输之前,必须使能SPI发送和接收触发DAM传输请求,官方固件库中的函数分别为:SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE);和SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Tx , ENABLE);

2、    每轮DMA传输完成后,需在次启动一轮DMA传输之前,需要重新设置传输数据计数器:DMA_SetCurrDataCounter(DMA1_Channel2,256);和DMA_SetCurrDataCounter(DMA1_Channel3,256);

另外,我在使用上述方法的时候,忽然发现一个致命的问题:如果使用DMA控制STM32作为SPI主机输出数据,那么谁来产生片选信号CS呢?后来尝试过将NSS(PA4——SPI1或PB12——SPI2)管脚配置给SPI口,并改由硬件来控制该管脚:  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;结果发现均不奏效,也就是说:在SPI主模式下使用DMA发送,无法产生有效的片选CS信号!这无疑是致命的缺陷!——也许是我的理解不到位,请各位知道怎么解决这个问题的大神一定要高速我一下。(当然这一缺陷,对于无需在单次发送字节/半字之后给出片选CS信号的应用——如大容量SPI接口存储器,并不成其为问题。)

无法在用DMA控制SPI发送时控制CS信号,我只好退而求其次:改由软件控制SPI发送,并同步产生CS信号。但这样做已经失去了DMA接收SPI的意义,因为软件控制SPI发送后,通信的速度和使用查询法是一样的!

2、SPI接收使用DMA控制,发送使用软件控制

尽管我认为发送使用软件控制后,DMA在接收中带来的好处已经基本丧失,但在这里仍然给出主程序中收发控制程序供读者参考。

  1. 1 SPIx_Init();
  2. 2 DMA_Config(256);//配置DMA的SPI通道,数据深度设为256
  3. 3 SPI_I2S_DMACmd(SPI1 , SPI_I2S_DMAReq_Rx , ENABLE);
  4. 4 delay_ms(300);
  5. 5 while(1)
  6. 6 {
  7. 7 while(n_interrupt != 0);//等到中断到来
  8. 8 while(n_interrupt == 0);//等到中断结束
  9. 9 DMA_SetCurrDataCounter(DMA1_Channel2,256);//这部必须在每次启动DMA之前设置,
  10. 10 DMA_Cmd(DMA1_Channel2, ENABLE); //使能DMA所指示的通道
  11. 11 for(k = 0 ; k < 256 ; k++)
  12. 12 {
  13. 13 CS = 0;
  14. 14 SPIx_ReadWrite16bit(0xaa55);//只使用了DMA接收SPI数据,但接收要由软件启动发送数据才能接收,此处只是随便发送了一个数据
  15. 15 CS = 1;
  16. 16 }
  17. 17 if(DMA_GetFlagStatus(DMA1_FLAG_TC2)!=RESET) //判断通道2传输完成
  18. 18 DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志
  19. 19 DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA
  20. 20 //////////以下可以把数据传输走//////////
  21. 21
  22. 22 }

SPI主机,软件控制逐字发送,接收用DMA控制

可以看到,当由软件控制SPI发送后,就可以由软件产生和发送同步的片选CS了。但这样做与收发都采用查询法的效率几乎一样了。

特别的,当采用查询法直接控制SPI口的接收和发送时,硬件的读写和软件的指令总是存在较大时间空隙:向SPI数据寄存器SPI_DR写入数据到SPI实际发出数据之间存在至少200ns间隔;检测SPI状态寄存器SPI_SR中的TXE(发送缓冲区空位)时,TXE位的变化总是比实际发送完成晚至少200ns。例如上面的代码,函数SPIx_ReadWrite16bit();通过软件控制片选CS信号和SPI硬件的方式通信,下图是它所产生的CS信号(蓝)和SCK(黄),可以发现该函数用于发送的时间只占了实际耗费时间的一半以下,特别是当发送字长仅为8bits时,时间利用率真的是非常感人。

查询法实现片选CS信号(蓝色)和SPI硬件产生的时序

对于这样的实时性,我实在是不明白意法半导体的STM32设计师的初衷是什么。当然,也有可能是笔者才疏学浅,如果有大神知道,烦请转告,多谢!

二、STM32做SPI从机(Slave)时的DMA传输

当然用DMA读写SPI,更合理的方式是让STM32的SPI工作在从机模式,只要主机给出合理的片选CS、时钟SCK和数据MOSI/MISO信号,作为从机的STM32就能在DMA的支持下,实现高效、实时的数据接收。下面的代码中,我将SPI1配置为从机模式,用DMA1CH2接收数据。

  1. 1 /////// DMA CH2配置代码/////////
  2. 2 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
  3. 3 DMA_DeInit(DMA1_Channel2); //将DMA的通道1寄存器重设为缺省值
  4. 4 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); //DMA外设基地址
  5. 5 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)spi_rx_buff; //DMA内存基地址
  6. 6 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取数据到内存
  7. 7 DMA_InitStructure.DMA_BufferSize = num; //DMA通道的DMA缓存的大小
  8. 8 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
  9. 9 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
  10. 10 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
  11. 11 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
  12. 12 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式
  13. 13 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有中优先级
  14. 14 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
  15. 15 DMA_Init(DMA1_Channel2, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
  16. 16 /////// SPI1配置代码/////////
  17. 17 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );
  18. 18 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;//PA4 PA5 6 7是SPI1的CS SCK MIOS MOSI
  19. 19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  20. 20 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  21. 21 GPIO_Init(GPIOA, &GPIO_InitStructure);
  22. 22 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  23. 23 SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //设置SPI工作模式:设置为SPI从机
  24. 24 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收8位帧结构
  25. 25 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //空闲时时钟为低电平
  26. 26 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿
  27. 27 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //SPI_NSS_Hard; ////NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  28. 28 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //定义波特率预分频的值
  29. 29 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  30. 30 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
  31. 31 SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

SPI从机DMA使用流程

主程序中,控制DMA和读取缓冲中的程序如下所示。这里为了代码的简单易懂,同样没有使用DMA中断,在实际使用时,建议读者使用中断以提高数据读写效率。

  1. 1 SPI_Cmd(SPI1, ENABLE); //使能SPI1外设
  2. 2 DMA_SetCurrDataCounter(DMA1_Channel2,256);//这部必须在每次启动DMA之前设置,
  3. 3 DMA_Cmd(DMA1_Channel2, ENABLE); //使能DMA所指示的通道
  4. 4 while(DMA_GetFlagStatus(DMA1_FLAG_TC2)==RESET); //判断通道2传输完成
  5. 5 DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志
  6. 6 DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA
  7. 7 SPI_Cmd(SPI1, DISABLE); //禁止SPI,只在开启SPI时接收数据,防止主机不断发送
  8. 8 //////////以下可以把数据传输走//////////
  9. 9 for(i=0;i<256;i++)
  10. 10 data_repo_short[i] = spi_rx_buff[i];

SPI从机配置代码

下图是我用FPGA作为SPI主机产生的读写时序,可以看到此时SPI可以达到很高的通信效率。提高SCK的主频后,通信速度上限10Mbytes/S左右(主要受限于STM32的接收SCK频率)。

FPGA产生的SPI主机时序,STM32做从机

三、总结

STM32的SPI接口并不完美,仍然存在各种小问题,尤其是在SPI作为主机受DMA控制传输大量数据时,效率并不能得到很大提升。但当STM32的SPI作为从机时,DMA控制的数据传输,能够较大的提升数据常数效率。

STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]的更多相关文章

  1. STM32基于HAL库通过DMA读写SDIO

    通过STM32CUBEMX生成DMA读写sdio的工程,再读写过程中总会卡死在DMA中断等待读写完成的while中,最终发现while等待的标志在SDIO的中断里置位的,而SDIO中断优先级如果小于或 ...

  2. 国产CPLD(AGM1280)试用记录——做个SPI接口的任意波形DDS [原创www.cnblogs.com/helesheng]

    我之前用过的CPLD有Altera公司的MAX和MAX-II系列,主要有两个优点:1.程序存储在片上Flash,上电即行,保密性高.2.CPLD器件规模小,成本和功耗低,时序不收敛情况也不容易出现.缺 ...

  3. 给初学者的STM32(Cortex-M3)中断原理及编程方法介绍 [原创www.cnblogs.com/helesheng]

    本人编著的<基于STM32的嵌入式系统原理及应用>(ISBN:9787030697974)刚刚在科学出版社出版.这本书花费了半年以上的时间,凝聚了笔者作为高校教师和嵌入式工程师的一些经验, ...

  4. RS485自动收发切换电路 [原创www.cnblogs.com/helesheng]

    RS485是最常见的一种远距离可靠传输和组网的UART串口信号接口协议.与同样传输UART串口信号的RS422协议相比,RS485使用半双工通信,即只有一个信道,在同一时刻要么从A到B,要么从B到A传 ...

  5. LabVIEW生成.NET的DLL——C#下调用NI数据采集设备功能的一种方法 [原创www.cnblogs.com/helesheng]

    LabVIEW是NI公司的数据采集设备的标准平台,在其上调用NI-DAQmx驱动和接口函数能够高效的开发数据采集和控制程序.但作为一种图形化的开发语言,使用LabVIEW开发涉及算法和流程控制的大型应 ...

  6. oled stm32的spi

    其实各种协议是很重要的,这篇文章就当做我对spi协议的一个整理吧. 必要的spi简介: https://www.cnblogs.com/zengsf/p/7221207.html?utm_source ...

  7. STM32F10X SPI操作flash MX25L64读写数据(转)

    源:STM32F10X SPI操作flash MX25L64读写数据 前一段时间在弄SPI,之前没接触过嵌入式外围应用,就是单片机也只接触过串口通信,且也是在学校的时候了.从离开手机硬件测试岗位后,自 ...

  8. SPI操作flash MX25L64读写数据

    STM32F10X SPI操作flash MX25L64读写数据 简单的一种应用,ARM芯片作为master,flash为slaver,实现单对单通信.ARM主控芯片STM32F103,flash芯片 ...

  9. STM32的IO口的8种配置

    STM32的IO口的8种配置 1 STM32的输入输出管脚有以下8种可能的配置:(4输入+2输出+2复用输出) ① 浮空输入_IN_FLOATING ② 带上拉输入_IPU ③ 带下拉输入_IPD ④ ...

随机推荐

  1. &&与||的优先级比较

    &&与||的优先级比较类似于一种思维体操,更多的是造成矛盾,使得两者因为先后顺序的不同而造成的不同结果,当然有时候需要注意c语言中的短路运算. 方法1. 代码如下: 点击查看代码 #i ...

  2. dijkstra最短路算法(堆优化)

    这个算法不能处理负边情况,有负边,请转到Floyd算法或SPFA算法(SPFA不能处理负环,但能判断负环) SPFA(SLF优化):https://www.cnblogs.com/yifan0305/ ...

  3. linux学习随笔2之防火墙

    centos7默认使用的防火墙是firewalld 查看所有打开的端口: firewall-cmd --zone=public --list-ports 更新防火墙规则: firewall-cmd - ...

  4. npm run dev 启动项目报错我的解决办法

    我的报错截屏 解决方案   1.    config文件中 index 文件中的 host 值如果是数字串就将其改为 localhost 2.    再次尝试 如果有遇到其他问题阔以将 node-mo ...

  5. Computational Protein Design with Deep Learning Neural Networks

    本文使用深度神经网络完成计算蛋白质设计去预测20种氨基酸概率. Introduction 针对特定结构和功能的蛋白质进行工程和设计,不仅加深了对蛋白质序列结构关系的理解,而且在化学.生物学和医学等领域 ...

  6. 使用 DolphinScheduler 调度 Kylin 构建

    本文章经授权转载 Apache Kylin 上游通常有复杂的数据 ETL 过程,如 Hive 入库.数据清洗等:下游有报表刷新,邮件分发等.集成 Apache DolphinScheduler 后,K ...

  7. .NET 6应用程序适配国产银河麒麟V10系统随记

    最近想在麒麟系统上运行.NET 6程序,经过一番折腾最终完成了,简单记录一下. 目标系统: CPU: aarch64架构(ARM64) 操作系统:银河麒麟V10高级服务器系统 银河麒麟V10系统(以下 ...

  8. JavaScript基础回顾知识点记录4-正则表达式篇(介绍基本使用)

    js 中 正则表达式使用 创建正则对象和test方法使用 /* 创建正则表达式的对象 语法: var 变量 = new RegExp("正则表达式","匹配模式" ...

  9. Minio分布式集群部署——Swarm

    最近研究minio分布式集群部署,发现网上大部分都是单服务器部署,而minio官方在github上现在也只提供了k8s和docker-compose的方式,网上有关与swarm启动minio集群的文章 ...

  10. 刷题记录:Codeforces Round #719 (Div. 3)

    Codeforces Round #719 (Div. 3) 20210703.网址:https://codeforces.com/contest/1520. 没错,我是个做div3的蒟蒻-- A 大 ...