Moin :-)
Ich steuere erfolgreich mit einem STM32L151CC ein TFT Display mit
ILI9341 per SPI an. Da das viel zu langsam läuft versuche ich es jetzt
mit SPI über DMA und bekomme bisher nicht mal eine Reaktion vom Display
:-(
Die Funktionen "Fill" und "DrawPixel" senden (wie bei SPI) je nur ein
byte an das Display. Das macht per DMA natürlich keinen Sinn, aber es
ist auch nur zum Testen. Hauptsache da tut sich überhaupt mal was...
Beim Debug springe ich in die Funktion "DMA1_Channel4_IRQHandler".
Daher nehme ich an, dass die Kommunikation grundlegend funktioniert(?).
Könnte da mal bitte jemand drüber schauen? Verstehe ich da noch etwas
grundlegend falsch?
Gruß,
Martin
#include "stm32l1xx_rcc.h"
#include "stm32l1xx_gpio.h"
#include "stm32l1xx_dma.h"
#include "stm32l1xx_spi.h"
#include "misc.h"
#include "ili9341.h"
void InitLCD(void);
void Fill(uint32_t color);
void DrawPixel(uint16_t x, uint16_t y, uint32_t color);
uint16_t SPIBuffer[] = {0xAAAA, 0xAAAA, 0xAAAA};
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
SystemInit();
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
/*
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
//GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2);
*/
// PB11 RST
// PB12 CS
// PB15 MOSI
// PB14 DC/MISO
// PB13 SCK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_12, SET);
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_Cmd(SPI2, ENABLE);
// DMA Channel 4 - SPI RX
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPIBuffer;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
// DMA Channel 5 - SPI TX
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPIBuffer;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
InitLCD();
//Fill(0xFFFF);
DrawPixel(50,50,0xFFFF);
while(1)
{
}
}
void SendCommand(uint16_t data) {
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_Cmd(DMA1_Channel5, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4, 1);
DMA_SetCurrDataCounter(DMA1_Channel5, 1);
SPIBuffer[0] = data;
//SPIBuffer[1] = 0x5678;
// Chip Select Low
ILI9341_WRX_RESET;
//ILI9341_CS_RESET;
GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET);
DMA_Cmd(DMA1_Channel4, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
void SendData(uint16_t data) {
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_Cmd(DMA1_Channel5, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4, 1);
DMA_SetCurrDataCounter(DMA1_Channel5, 1);
SPIBuffer[0] = data;
// Chip Select Low
ILI9341_WRX_SET;
//ILI9341_CS_RESET;
GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET);
DMA_Cmd(DMA1_Channel4, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
void SetCursorPosition(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t
y2) {
SendCommand(0x2A);
SendData(x1 >> 8);
SendData(x1 & 0xFF);
SendData(x2 >> 8);
SendData(x2 & 0xFF);
SendCommand(0x2B);
SendData(y1 >> 8);
SendData(y1 & 0xFF);
SendData(y2 >> 8);
SendData(y2 & 0xFF);
}
void Fill(uint32_t color) {
unsigned int n, i, j;
i = color >> 8;
j = color & 0xFF;
SetCursorPosition(0, 0, 239, 319);
SendCommand(ILI9341_GRAM);
for (n = 0; n < 76800; n++) {
SendData(i);
SendData(j);
}
}
void DrawPixel(uint16_t x, uint16_t y, uint32_t color) {
SetCursorPosition(x, y, x, y);
SendCommand(ILI9341_GRAM);
SendData(color >> 8);
SendData(color & 0xFF);
}
void InitLCD(void){
unsigned int i = 0;
ILI9341_RST_SET;
SendCommand(ILI9341_RESET);
for(i=0;i<500000;i++);
SendCommand(ILI9341_POWERA);
SendData(0x39);
SendData(0x2C);
SendData(0x00);
SendData(0x34);
SendData(0x02);
SendCommand(ILI9341_POWERB);
SendData(0x00);
SendData(0xC1);
SendData(0x30);
SendCommand(ILI9341_DTCA);
SendData(0x85);
SendData(0x00);
SendData(0x78);
SendCommand(ILI9341_DTCB);
SendData(0x00);
SendData(0x00);
SendCommand(ILI9341_POWER_SEQ);
SendData(0x64);
SendData(0x03);
SendData(0x12);
SendData(0x81);
SendCommand(ILI9341_PRC);
SendData(0x20);
SendCommand(ILI9341_POWER1);
SendData(0x23);
SendCommand(ILI9341_POWER2);
SendData(0x10);
SendCommand(ILI9341_VCOM1);
SendData(0x3E);
SendData(0x28);
SendCommand(ILI9341_VCOM2);
SendData(0x86);
SendCommand(ILI9341_MAC);
SendData(0x48);
SendCommand(ILI9341_PIXEL_FORMAT);
SendData(0x55);
SendCommand(ILI9341_FRC);
SendData(0x00);
SendData(0x18);
SendCommand(ILI9341_DFC);
SendData(0x08);
SendData(0x82);
SendData(0x27);
SendCommand(ILI9341_3GAMMA_EN);
SendData(0x00);
SendCommand(ILI9341_COLUMN_ADDR);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendData(0xEF);
SendCommand(ILI9341_PAGE_ADDR);
SendData(0x00);
SendData(0x00);
SendData(0x01);
SendData(0x3F);
SendCommand(ILI9341_GAMMA);
SendData(0x01);
SendCommand(ILI9341_PGAMMA);
SendData(0x0F);
SendData(0x31);
SendData(0x2B);
SendData(0x0C);
SendData(0x0E);
SendData(0x08);
SendData(0x4E);
SendData(0xF1);
SendData(0x37);
SendData(0x07);
SendData(0x10);
SendData(0x03);
SendData(0x0E);
SendData(0x09);
SendData(0x00);
SendCommand(ILI9341_NGAMMA);
SendData(0x00);
SendData(0x0E);
SendData(0x14);
SendData(0x03);
SendData(0x11);
SendData(0x07);
SendData(0x31);
SendData(0xC1);
SendData(0x48);
SendData(0x08);
SendData(0x0F);
SendData(0x0C);
SendData(0x31);
SendData(0x36);
SendData(0x0F);
SendCommand(ILI9341_SLEEP_OUT);
for(i=0;i<250000;i++);
SendCommand(ILI9341_DISPLAY_ON);
SendCommand(ILI9341_GRAM);
}
void spi_handleDMA1Ch4Interrupt(void){
// Chip Select High
GPIO_WriteBit(GPIOB, GPIO_Pin_12, SET);
}
void DMA1_Channel4_IRQHandler(void){
spi_handleDMA1Ch4Interrupt();
DMA_ClearFlag(DMA1_FLAG_TC4);
}
Der DMA Interrupt sagt nur das das letzte Byte in das SPI Datenregister geschrieben wurde. Damit ist es aber noch nicht gesendet! Du ziehst also CS zu früh hoch.
Stimmt.. DMA_Cmd(DMA1_Channel4, ENABLE); DMA_Cmd(DMA1_Channel5, ENABLE); while (DMA_GetFlagStatus(DMA1_FLAG_TC5) == RESET); Wäre es so richtig? Das führt in eine Endlos-Schleife... :-(
holger schrieb: > Der DMA Interrupt sagt nur das das letzte Byte in das > SPI Datenregister geschrieben wurde. Damit ist es aber > noch nicht gesendet! Du ziehst also CS zu früh hoch. Schwachsinn. Der DMA IRQ ist für RX Channel, und der kommt offensichtlich erst wenn der Transfer beendet wurde. Das Problem des OP ist, dass er IMO nicht auf den Interrupt wartet bevor das nächste Wort gesendet wird.
So hatte ich es auch gelesen. Der IRQ vom Rx kommt sobald der Transfer beendet ist. Aber müsste "DMA1_FLAG_TC5" dann nicht gesetzt sein? Bzw. "DMA1_FLAG_TC4"? Werden beide nicht gesetzt...
Update: Nachdem ich die Reihenfolge "Channel ENABLE" und "CS Low" geändert habe, kann ich das Setzen der u.g. Flags abwarten. Also schonmal keine Endlos-Schleife mehr. Hat sich leider trotzdem noch nix am Display getan... DMA_Cmd(DMA1_Channel4, DISABLE); DMA_Cmd(DMA1_Channel5, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel4, 1); DMA_SetCurrDataCounter(DMA1_Channel5, 1); SPIBuffer[0] = data; ILI9341_WRX_RESET; DMA_Cmd(DMA1_Channel4, ENABLE); DMA_Cmd(DMA1_Channel5, ENABLE); // Chip Select Low GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET); while (!DMA_GetFlagStatus(DMA1_FLAG_TC5)); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
Martin Petri schrieb: > DMA_Cmd(DMA1_Channel4, ENABLE); > DMA_Cmd(DMA1_Channel5, ENABLE); > > // Chip Select Low > GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET); Das ist aber ein übles Race. CS kommt so praktisch immer etwas zu spät. Das CS Low kann viel zu spät kommen, sobald andere Interrupts aktiv sind. Dein Handler nimmt nach jedem empfangenen Wort CS wieder hoch, ist das überhaupt korrekt? Ich kenne das so, das CS für das ganze Kommando aktiv low sein muss.
Ja, das hab' ich mir gestern Abend auch schon überlegt. Ist wohl eher Zufall, dass DMA1_FLAG_TC5 anschließend passt. Mir ist noch nicht klar, wie man die Initialisierung in einem Schwung an den ILI9341 übergibt. Beim "Command" muss RS (ILI9341_WRX_SET) ja 0 sein und beim Daten senden 1. Ich hab keine Idee wie ich das zwischendurch wechseln könnte, wenn ich die Initialisierungs-Bytes in den Buffer packe und abschicke. Oder macht man die Initialisierung noch per SPI ohne DMA und wechselt dann in einen DMA Modus...(?)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.