Mit dieser Library kann der STM32F4 als SPI-Slave eingesetzt werden.
Der Slave simuliert ein 256-Byte großes SPI-RAM. Die SPI-Funktionen laufen per Interrupt ab. Es gibt zwei Funktionen für read/write vom internen RAM.
Ein SPI-Master kann über Kommandos ein Byte in das interne RAM vom Slave speichern, ein Byte aus dem RAM vom Slave auslesen oder eine ID-Nummer vom Slave abfragen.
(Der SPI-Mode vom Master und Slave muss dabei gleich sein !!)
Die 3 Kommdos die implementiert sind, sind alle 3 Bytes lang :
1 2 3 4 5 6 7 8 9 10 11 | CMD-01 = Read ID Master : 0x01 ,Dummy,Dummy Slave : Dummy,0x32 ,0x07 CMD-02 = Write Byte Master : 0x02 ,Adr ,Value Slave : Dummy,Dummy,Dummy CMD-03 = Read Byte Master : 0x03 ,Adr ,Dummy Slace : Dummy,Dummy,Value |
Im Beispiel wartet der Slave solange, bis ein Master per SPI in die RAM-Adresse 0×00 den Wert 0×12 geschrieben hat, dann wird die grüne LED eingeschaltet.
die SPI-Pins die benutzt werden sollen, müssen im C-File eingetragen werden
(im H-File kann die Größe vom RAM eingestellt werden)
es gibt 3 identische Librarys, getrennt für SPI1, SPI2 und SPI3
im Beispiel wurde SPI2 benutzt mit dieser Pinbelegung :
1 2 3 4 | SCK an PB13 MOSI an PB15 MISO an PC14 SlaveSelect an PB12 |
Voraussetzungen :
1 2 | Benutzte Module der CooCox-IDE : GPIO, SPI, MISC Benutzte Librarys : keine |
Enumeration :
1 2 3 4 5 6 7 8 9 10 | typedef enum { SPI_SMODE_0_MSB = 0, // CPOL=0, CPHA=0 (MSB-First) SPI_SMODE_1_MSB, // CPOL=0, CPHA=1 (MSB-First) SPI_SMODE_2_MSB, // CPOL=1, CPHA=0 (MSB-First) SPI_SMODE_3_MSB, // CPOL=1, CPHA=1 (MSB-First) SPI_SMODE_0_LSB, // CPOL=0, CPHA=0 (LSB-First) SPI_SMODE_1_LSB, // CPOL=0, CPHA=1 (LSB-First) SPI_SMODE_2_LSB, // CPOL=1, CPHA=0 (LSB-First) SPI_SMODE_3_LSB // CPOL=1, CPHA=1 (LSB-First) }SPI2_SMode_t; |
Funktionen (für SPI2) :
1 2 3 | ErrorStatus UB_SPI2_Slave_Init(SPI2_SMode_t mode); // zum init als SPI-Slave uint8_t UB_SPI2_Slave_ReadByte(uint8_t adr); // zum lesen vom RAM void UB_SPI2_Slave_WriteByte(uint8_t adr, uint8_t wert); // zum schreiben in das RAM |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | //-------------------------------------------------------------- // File : main.c // Datum : 01.02.2014 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.4 // GCC : 4.7 2012q4 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der SPI-Slave-Library // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_led.h" #include "stm32_ub_spi2_slave.h" int main(void) { uint8_t wert; SystemInit(); // Quarz Einstellungen aktivieren // init der LEDs UB_Led_Init(); // init vom SPI-2 im Slave-Mode UB_SPI2_Slave_Init(SPI_SMODE_0_MSB); while(1) { // Wert vom RAM an Adresse 0x00 auslesen wert=UB_SPI2_Slave_ReadByte(0x00); // LEDs je nach Inhalt schalten if(wert==0x12) { UB_Led_On(LED_GREEN); UB_Led_Off(LED_RED); } else { UB_Led_On(LED_RED); UB_Led_Off(LED_GREEN); } } } |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Thank you very much for sharing this,
I downloaded your example and modified to my stm32f3discovery board and it works. I have question about the NSS pin that I guess it is a CS pin but the NSS pin is disconnected, the SPI2_IRQHandler() still interrupt so, I worry when connect my board to another spi devices, it will has error. Please share how to make the NSS pin as a real CS pin.
Thanks in advance.
I sent you an email in the morning, Now I have changed
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
//////////////////////////////// Code /////////////////////////////////
// SPI als Alternative-Function mit PullDown
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
/////////////////////////////////////////////////////////////////////
and it seems to be working, the spi slave can send data when the NSS (CS) is LOW.
Just asking you is it correct?
Best regards,
Sakarin
Hi Sakarin,
If you have only one slave than your modification is ok.
But if you have more than one spi-slave on this bus you have to connect
the SlaveSelect-Pin (PB12 in this demo) with the master !
Hi,
Thanks again for your answer.
Now, I am trying to move the code to use DMA but it does not work. Could you share about the modification to use DMA?
Best regards,
Sakarin
i dont have a spi-dma demo. but ST has one “STM32F4xx_StdPeriph_Examples\SPI\SPI_TwoBoards\SPI_DataExchangeDMA”
Thank you very much your suggestion. I tried to understand it but it gets data on the main program. Do you have some examples to work on SPI2 with DMA interrupt?
// SPI2_RX //
void DMA1_Channel4_IRQHandler(void)
{
}
//SPI2_TX //
void DMA1_Channel5_IRQHandler(void)
{
}
I wrote my code and it can enter to interrupts above when receive spi message but don’t know how to read the receiving data from spi in debug mode of CooCox.
void SPI_Slave_and_DMA_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure; //Variable used to setup the SPI
DMA_InitTypeDef DMA_InitStructure; //Variable used to setup the DMA
// SPI-Clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
// Clock Enable der Pins, GPIOB
RCC_AHBPeriphClockCmd(SPI2DEV.SCK.CLK, ENABLE);
RCC_AHBPeriphClockCmd(SPI2DEV.MOSI.CLK, ENABLE);
RCC_AHBPeriphClockCmd(SPI2DEV.MISO.CLK, ENABLE);
RCC_AHBPeriphClockCmd(SPI2DEV.NSS.CLK, ENABLE);
// SPI Alternative-Functions mit den IO-Pins verbinden
GPIO_PinAFConfig(SPI2DEV.SCK.PORT, SPI2DEV.SCK.SOURCE, GPIO_AF_5);
GPIO_PinAFConfig(SPI2DEV.MOSI.PORT, SPI2DEV.MOSI.SOURCE, GPIO_AF_5);
GPIO_PinAFConfig(SPI2DEV.MISO.PORT, SPI2DEV.MISO.SOURCE, GPIO_AF_5);
GPIO_PinAFConfig(SPI2DEV.NSS.PORT, SPI2DEV.NSS.SOURCE, GPIO_AF_5);
// SPI als Alternative-Function mit PullDown
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // ok
// SCK-Pin
GPIO_InitStructure.GPIO_Pin = SPI2DEV.SCK.PIN;
GPIO_Init(SPI2DEV.SCK.PORT, &GPIO_InitStructure);
// MOSI-Pin
GPIO_InitStructure.GPIO_Pin = SPI2DEV.MOSI.PIN;
GPIO_Init(SPI2DEV.MOSI.PORT, &GPIO_InitStructure);
// MISO-Pin
GPIO_InitStructure.GPIO_Pin = SPI2DEV.MISO.PIN;
GPIO_Init(SPI2DEV.MISO.PORT, &GPIO_InitStructure);
// NSS-Pin
GPIO_InitStructure.GPIO_Pin = SPI2DEV.NSS.PIN;
GPIO_Init(SPI2DEV.NSS.PORT, &GPIO_InitStructure);
// Reset SPI Interface
SPI_I2S_DeInit(SPI2);
//== SPI2 configuration
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
//–Enable DMA1 clock–
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//==Configure DMA1 – Channel4== (SPI -> memory)
DMA_DeInit(DMA1_Channel4); //Set DMA registers to default values
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SPIReceivedValue[0]; //Variable to which received data will be stored
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1; //Buffer size
// DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
// DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure); //Initialise the DMA
DMA_Cmd(DMA1_Channel4, ENABLE); //Enable the DMA1 – Channel4
//==Configure DMA1 – Channel5== (memory -> SPI)
DMA_DeInit(DMA1_Channel5); //Set DMA registers to default values
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SPITransmittedValue[0]; //Variable from which data will be transmitted
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 1; //Buffer size
// DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
// DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //Initialise the DMA
DMA_Cmd(DMA1_Channel5, ENABLE); //Enable the DMA1 – Channel5
// Enable SPI2
SPI_Cmd(SPI2, ENABLE);
// Enable the SPI2 RX & TX DMA requests
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
}
if you need SPI-Master with DMA you can try this new Library :
http://mikrocontroller.bplaced.net/wordpress/?page_id=4593
Thank you! now I have fixed the code and it is working as I wish.