[APLIKACJA] STM32 i monochromatyczny wyświetlacz OLED
Na rysunku 4 pokazano sekwencję zapisywania danych przez mastera do slave.
Rys. 4. Sekwencja zapisania danych na magistrali I2C
Z zadaniami wykonywanymi przez mastera na magistrali są związane zdarzenia (events, EV):
- EV5: SB1, zerowana po odczytaniu rejestru SR1 . Po tym jest zapisywany rejestr DR z bajtem adresu slave uzupełnionym o bit R/W=0
- EV6: ADDR=1, ustawiany w rejestrze SR1, zerowany przez odczytanie rejestru SR2
- EV8_1: TxE=1, rejestr przesuwny jest pusty, rejestr danych jest pusty, zapisanie danej do rejestru DR
- EV8: TxE=1, rejestr przesuwny nie jest pusty, rejestr danych jest pusty, zerowany przez zapis rejestru DR
- EV8_2:, TxE=1, BTF=1 – żądanie sekwencji STOP. TxE i BTF zerowany sprzętowo przez sekwencję STOP
Nota aplikacyjna zawiera procedurę wysyłania przez I2C zawartości bufora z danymi. Jej argumentami są: numer interfejsu (I2C1, lub I2C2) wskaźnik na bufor z danymi, ilość danych do wysłania, tryb pracy i adres slave. Możliwe są 3 tryby pracy: polling, interrupt i DMA, z których zweryfikowano dwa: polling i DMA.
Na listingu 3 pokazano procedurę wysyłania do sterownika wyświetlacza zawartości bufora w trybie polling. W pierwszej kolejności jest inicjowana sekwencja START. Zakończenie tej sekwencji jest sygnalizowane przez wyzerowanie bitu SB (zdarzenie EV5). Jeżeli sekwencja START nie zakończy się w określonym czasie, to procedura kończy działanie i zwraca kod błędu. Po sekwencji START jest wysyłany adres SLAVE przez zapisanie jego wartości do rejestru DR. Wysłanie adresu i odebranie bitu potwierdzenia A jest sygnalizowane ustawieniem bitu ADDR. Jeżeli wszystko przebiega poprawnie, to można zapisywać w pętli kolejne dane do rejestru DR. Wysłanie kompletnej danej jest sygnalizowane ustawieniem bitu TxE.
List. 3. Wysyłanie zawartości bufora do kontrolera wyświetlacza w trybie polling
else if (Mode == Polling) /* I2Cx Master Transmission using Polling */ { Timeout = 0xFFFF; /* Send START condition */ I2Cx->CR1 |= CR1_START_Set; /* Wait until SB flag is set: EV5 */ while ((I2Cx->SR1&0x0001) != 0x0001) { if (Timeout-- == 0) return Error; } /* Send slave address */ /* Reset the address bit0 for write*/ //SlaveAddress &= OAR1_ADD0_Reset; Address = SlaveAddress; /* Send the slave address */ I2Cx->DR = Address; Timeout = 0xFFFF; /* Wait until ADDR is set: EV6 */ while ((I2Cx->SR1 &0x0002) != 0x0002) { if (Timeout-- == 0) return Error; } /* Clear ADDR flag by reading SR2 register */ temp = I2Cx->SR2; /* Write the first data in DR register (EV8_1) */ I2Cx->DR = *pBuffer; /* Increment */ pBuffer++; /* Decrement the number of bytes to be written */ NumByteToWrite--; /* While there is data to be written */ while (NumByteToWrite--) { /* Poll on BTF to receive data because in polling mode we can not guarantee the EV8 software sequence is managed before the current byte transfer completes */ while ((I2Cx->SR1 & 0x00004) != 0x000004); /* Send the current byte */ I2Cx->DR = *pBuffer; /* Point to the next byte to be written */ pBuffer++; } /* EV8_2: Wait until BTF is set before programming the STOP */ while ((I2Cx->SR1 & 0x00004) != 0x000004); /* Send STOP condition */ I2Cx->CR1 |= CR1_STOP_Set; /* Make sure that the STOP bit is cleared by Hardware */ while ((I2Cx->CR1&0x200) == 0x200); }
Na listingu 4 pokazano procedurę wysyłania zawartości bufora do kontrolera wyświetlacza z wykorzystaniem kanału DMA.
List. 4. Wysyłanie zawartości bufora do kontrolera wyświetlacza w trybie DMA
if (Mode == DMA) /* I2Cx Master Transmission using DMA */ { Timeout = 0xFFFF; /* Configure the DMA channel for I2Cx transmission */ I2C_DMAConfig (I2Cx, pBuffer, NumByteToWrite, I2C_DIRECTION_TX); /* Enable the I2Cx DMA requests */ I2Cx->CR2 |= CR2_DMAEN_Set; /* Send START condition */ I2Cx->CR1 |= CR1_START_Set; /* Wait until SB flag is set: EV5 */ while ((I2Cx->SR1&0x0001) != 0x0001) { if (Timeout-- == 0) return Error; } Timeout = 0xFFFF; /* Send slave address */ /* Reset the address bit0 for write */ SlaveAddress &= OAR1_ADD0_Reset; Address = SlaveAddress; /* Send the slave address */ I2Cx->DR = Address; /* Wait until ADDR is set: EV6 */ while ((I2Cx->SR1&0x0002) != 0x0002) { if (Timeout-- == 0) return Error; } /* Clear ADDR flag by reading SR2 register */ temp = I2Cx->SR2; if (I2Cx == I2C1) { /* Wait until DMA end of transfer */ while (!DMA_GetFlagStatus(DMA1_FLAG_TC6)); /* Disable the DMA1 Channel 6 */ DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE); /* Clear the DMA Transfer complete flag */ DMA_ClearFlag(DMA1_FLAG_TC6); } else /* I2Cx = I2C2 */ { /* Wait until DMA end of transfer */ while (!DMA_GetFlagStatus(DMA1_FLAG_TC4)); /* Disable the DMA1 Channel 4 */ DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE); /* Clear the DMA Transfer complete flag */ DMA_ClearFlag(DMA1_FLAG_TC4); } /* EV8_2: Wait until BTF is set before programming the STOP */ while ((I2Cx->SR1 & 0x00004) != 0x000004); /* Program the STOP */ I2Cx->CR1 |= CR1_STOP_Set; /* Make sure that the STOP bit is cleared by Hardware */ while ((I2Cx->CR1&0x200) == 0x200); }