niedziela, 23 lipca 2017

[3] STM32F429I - Discovery - LCD TFT oraz panel dotykowy, biblioteki STD

Ten post chciałbym poświęcić na opisanie obsługi wyświetlacza za pomocą interfejsu SPI, oraz programowanie panelu dotykowego za pomocą interfejsu I2C.

Wszystkie funkcje nie opisane w tym poście są wyjaśnione i można je pobrać na samym dole tego postu.

[http://www.st.com/en/evaluation-tools/32f429idiscovery.html]

Wyświetlacz:


W tym przypadku zamiast LTDC wykorzystałem SPI. Głównym powodem jest ograniczenie ilości linii transmisyjnych oraz tym, że występuje całkiem spora grupa wyświetlaczy TFT wykorzystujących komunikację po tym interfejsie. Dodatkowym atutem przy tym jest ich dosyć przyzwoita cena.

Inicjalizacja wyświetlacza odbywa się przez następującą funkcje:

  1. static void ili9341_InitDisplay(void)
  2. {
  3.   /* Configurate LCD */
  4.   ili9341_WriteCmdData(0xCA);
  5.   ili9341_WriteData(0xC3);
  6.   ili9341_WriteData(0x08);
  7.   ili9341_WriteData(0x50);
  8.   ili9341_WriteCmdData(LCD_POWERB);
  9.   ili9341_WriteData(0x00);
  10.   ili9341_WriteData(0xC1);
  11.   ili9341_WriteData(0x30);
  12.   ili9341_WriteCmdData(LCD_POWER_SEQ);
  13.   ili9341_WriteData(0x64);
  14.   ili9341_WriteData(0x03);
  15.   ili9341_WriteData(0x12);
  16.   ili9341_WriteData(0x81);
  17.   ili9341_WriteCmdData(LCD_DTCA);
  18.   ili9341_WriteData(0x85);
  19.   ili9341_WriteData(0x00);
  20.   ili9341_WriteData(0x78);
  21.   ili9341_WriteCmdData(LCD_POWERA);
  22.   ili9341_WriteData(0x39);
  23.   ili9341_WriteData(0x2C);
  24.   ili9341_WriteData(0x00);
  25.   ili9341_WriteData(0x34);
  26.   ili9341_WriteData(0x02);
  27.   ili9341_WriteCmdData(LCD_PRC);
  28.   ili9341_WriteData(0x20);
  29.   ili9341_WriteCmdData(LCD_DTCB);
  30.   ili9341_WriteData(0x00);
  31.   ili9341_WriteData(0x00);
  32.   ili9341_WriteCmdData(LCD_FRC);
  33.   ili9341_WriteData(0x00);
  34.   ili9341_WriteData(0x1B);
  35.   ili9341_WriteCmdData(LCD_DFC);
  36.   ili9341_WriteData(0x0A);
  37.   ili9341_WriteData(0xA2);
  38.   ili9341_WriteCmdData(LCD_POWER1);
  39.   ili9341_WriteData(0x10);
  40.   ili9341_WriteCmdData(LCD_POWER2);
  41.   ili9341_WriteData(0x10);
  42.   ili9341_WriteCmdData(LCD_VCOM1);
  43.   ili9341_WriteData(0x45);
  44.   ili9341_WriteData(0x15);
  45.   ili9341_WriteCmdData(LCD_VCOM2);
  46.   ili9341_WriteData(0x90);
  47.   ili9341_WriteCmdData(LCD_MAC);
  48.   ili9341_WriteData(0xC8);
  49.   ili9341_WriteCmdData(LCD_3GAMMA_EN);
  50.   ili9341_WriteData(0x00);
  51.   ili9341_WriteCmdData(LCD_RGB_INTERFACE);
  52.   ili9341_WriteData(0xC2);
  53.   ili9341_WriteCmdData(LCD_DFC);
  54.   ili9341_WriteData(0x0A);
  55.   ili9341_WriteData(0xA7);
  56.   ili9341_WriteData(0x27);
  57.   ili9341_WriteData(0x04);
  58.     /* Colomn address set */
  59.   ili9341_WriteCmdData(LCD_COLUMN_ADDR);
  60.   ili9341_WriteData(0x00);
  61.   ili9341_WriteData(0x00);
  62.   ili9341_WriteData(0x00);
  63.   ili9341_WriteData(0xEF);
  64.     /* Page adress set */
  65.   ili9341_WriteCmdData(LCD_PAGE_ADDR);
  66.   ili9341_WriteData(0x00);
  67.   ili9341_WriteData(0x00);
  68.   ili9341_WriteData(0x01);
  69.   ili9341_WriteData(0x3F);
  70.   ili9341_WriteCmdData(LCD_INTERFACE);
  71.   ili9341_WriteData(0x01);
  72.   ili9341_WriteData(0x00);
  73.   ili9341_WriteData(0x06);
  74.   ili9341_WriteCmdData(LCD_GRAM);
  75.   ili9341_Delay(LCD_INIT_PAUSE);
  76.   ili9341_WriteCmdData(LCD_GAMMA);
  77.   ili9341_WriteData(0x01);
  78.   ili9341_WriteCmdData(LCD_PGAMMA);
  79.   ili9341_WriteData(0x0F);
  80.   ili9341_WriteData(0x29);
  81.   ili9341_WriteData(0x24);
  82.   ili9341_WriteData(0x0C);
  83.   ili9341_WriteData(0x0E);
  84.   ili9341_WriteData(0x09);
  85.   ili9341_WriteData(0x4E);
  86.   ili9341_WriteData(0x78);
  87.   ili9341_WriteData(0x3C);
  88.   ili9341_WriteData(0x09);
  89.   ili9341_WriteData(0x13);
  90.   ili9341_WriteData(0x05);
  91.   ili9341_WriteData(0x17);
  92.   ili9341_WriteData(0x11);
  93.   ili9341_WriteData(0x00);
  94.   ili9341_WriteCmdData(LCD_NGAMMA);
  95.   ili9341_WriteData(0x00);
  96.   ili9341_WriteData(0x16);
  97.   ili9341_WriteData(0x1B);
  98.   ili9341_WriteData(0x04);
  99.   ili9341_WriteData(0x11);
  100.   ili9341_WriteData(0x07);
  101.   ili9341_WriteData(0x31);
  102.   ili9341_WriteData(0x33);
  103.   ili9341_WriteData(0x42);
  104.   ili9341_WriteData(0x05);
  105.   ili9341_WriteData(0x0C);
  106.   ili9341_WriteData(0x0A);
  107.   ili9341_WriteData(0x28);
  108.   ili9341_WriteData(0x2F);
  109.   ili9341_WriteData(0x0F);
  110.   ili9341_WriteCmdData(LCD_SLEEP_OUT);
  111.   ili9341_Delay(LCD_INIT_PAUSE);
  112.   ili9341_WriteCmdData(LCD_DISPLAY_ON);
  113.   /* Gram Start writing */
  114.   ili9341_WriteCmdData(LCD_GRAM);
  115. }

Uruchomienie interfejsu SPI:

  1. void SPI5_Initialization(void)
  2. {
  3.   GPIO_InitTypeDef  GPIO_InitStructure;
  4.   SPI_InitTypeDef  SPI_InitStructure;
  5.   /* Enable clock for SPI5 */
  6.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI5, ENABLE);
  7.   /* Enables clocks */
  8.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
  9.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
  10.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
  11.   /* Set pin as alternative */
  12.   GPIO_PinAFConfig(GPIOF, GPIO_PinSource7, GPIO_AF_SPI5);
  13.   GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_SPI5);
  14.   GPIO_PinAFConfig(GPIOF, GPIO_PinSource8, GPIO_AF_SPI5);
  15.     /* Set GPIO as alternative for SPI5 with pulldown */
  16.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  17.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  19.   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  20.   /* SCK pin */
  21.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  22.   GPIO_Init(GPIOF, &GPIO_InitStructure);
  23.    
  24.   /* MOSI pin */
  25.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  26.   GPIO_Init(GPIOF, &GPIO_InitStructure);
  27.    
  28.   /* MISO pin */
  29.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  30.   GPIO_Init(GPIOF, &GPIO_InitStructure);
  31.   SPI_I2S_DeInit(SPI5);
  32.     /* Configurate SPI */
  33.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  34.   SPI_InitStructure.SPI_Mode            = SPI_Mode_Master;
  35.   SPI_InitStructure.SPI_DataSize    = SPI_DataSize_8b;
  36.    
  37.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  38.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  39.    
  40.   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  41.   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
  42.   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  43.   SPI_InitStructure.SPI_CRCPolynomial = 7;
  44.   SPI_Init(SPI5, &SPI_InitStructure);
  45.   /* Enable SPI5 */
  46.   SPI_Cmd(SPI5, ENABLE);
  47. }

Uruchomienie pamięci SDRAM

  1. uint8_t SDRAM_Initialization(void)
  2. {
  3.     uint16_t read_value = 0;
  4.   uint16_t write_value = 0;
  5.   uint8_t operation_status = 0;
  6.   /* Init GPIO for SDRAM */
  7.   SDRAM_InitGpio();
  8.    
  9.   /* Init FMC */
  10.   SDRAM_InitFMC();
  11.     /* Initialization sequence */
  12.     SDRAM_Initialization_Sequence();
  13.    
  14.     /* Check if initialization went ok */
  15.   read_value=SDRAM_ReadData16b(0x00);
  16.   SDRAM_WriteData16b(0x00, 0xA5B6);
  17.   write_value=SDRAM_ReadData16b(0x00);
  18.   SDRAM_WriteData16b(0x00, read_value);
  19.    
  20.   if(write_value==0xA5B6){
  21.         operation_status=1; // RAM vorhanden
  22.     }
  23.     else{
  24.         operation_status = 0;
  25.     }
  26.   return operation_status;
  27. }

Init LTDC:

  1. static void ili9341_InitLTDC(void)
  2. {
  3.   LTDC_InitTypeDef       LTDC_InitStruct;
  4.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE);
  5.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);
  6.      
  7.   ili9341_AFConfigPins();    
  8.   LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL;
  9.   LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL;
  10.   LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL;
  11.   LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC;
  12.   LTDC_InitStruct.LTDC_BackgroundRedValue = 0;
  13.   LTDC_InitStruct.LTDC_BackgroundGreenValue = 0;
  14.   LTDC_InitStruct.LTDC_BackgroundBlueValue = 0;
  15.   RCC_PLLSAIConfig(192, 7, 4);
  16.   RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);
  17.   RCC_PLLSAICmd(ENABLE);
  18.   while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET);
  19.   LTDC_InitStruct.LTDC_HorizontalSync = 9;       // HSync-1
  20.   LTDC_InitStruct.LTDC_VerticalSync = 1;         // VSync-1
  21.   LTDC_InitStruct.LTDC_AccumulatedHBP = 29;      // HSync+HBP-1
  22.   LTDC_InitStruct.LTDC_AccumulatedVBP = 3;       // VSync+VBP-1
  23.   LTDC_InitStruct.LTDC_AccumulatedActiveW = 269; // HSync+HBP+W-1
  24.   LTDC_InitStruct.LTDC_AccumulatedActiveH = 323; // VSync+VBP+H-1
  25.   LTDC_InitStruct.LTDC_TotalWidth = 279;         // HSync+HBP+W+HFP-1
  26.   LTDC_InitStruct.LTDC_TotalHeigh = 327;         // VSync+VBP+H+VFP-1
  27.   LTDC_Init(&LTDC_InitStruct);
  28. }

Wypełnienie danej warstwy wybranym kolorem:

  1. void Tft_FillLayer(uint16_t color)
  2. {
  3.   uint32_t index = 0;
  4.   for (index = 0x00; index < ILI9341_FRAME_OFFSET; index+=2) {
  5.     *(__IO uint16_t*)(ILI9341_CurrentFrameBuffer + index) = color;
  6.   }
  7. }

Rysuj pojedynczy piksel na ekranie na podstawie globalnych ustawień kursora:

  1. void Tft_DrawPixel(uint16_t color)
  2. {
  3.   *(volatile uint16_t*)SetGlobalCursor=color;
  4.    
  5.   if(Tft_Display_Mode==Orientation_Portrait)
  6.     {
  7.     SetGlobalXCursor++;
  8.     if(SetGlobalXCursor>=ILI9341_X) {
  9.       SetGlobalXCursor=0;
  10.       SetGlobalXCursor++;
  11.       if(SetGlobalXCursor>=ILI9341_Y) SetGlobalXCursor=0;
  12.     }
  13.   }
  14.   else if(Tft_Display_Mode==Orientation_Landscape)
  15.     {
  16.     SetGlobalXCursor++;
  17.     if(SetGlobalXCursor>=ILI9341_Y) {
  18.       SetGlobalXCursor=0;
  19.       SetGlobalXCursor++;
  20.       if(SetGlobalXCursor>=ILI9341_X) SetGlobalXCursor=0;
  21.     }
  22.   }
  23.   SetGlobalCursor=ILI9341_CurrentFrameBuffer+(2*((SetGlobalXCursor*ILI9341_X)+SetGlobalXCursor));
  24. }

Funkcja rysująca piksel na ekranie w podanej lokalizacji:

  1. void TFT_DrawPixel_WithCords(uint16_t Xpos, uint16_t Ypos, uint32_t color)
  2. {
  3.     *(__IO uint16_t*)(SetGlobalCursor)=color;
  4.     SetGlobalCursor=ILI9341_CurrentFrameBuffer+(2*((Ypos*ILI9341_X)+Xpos));
  5. }

Rysowanie linii:

  1. void Tft_DrawLine(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t color)
  2. {
  3.      int steep = abs(y_end-y_start)>abs(x_end-x_start);
  4.      int dx=0;
  5.      int dy=0;
  6.      int err=0;
  7.      int ystep=0;
  8.        
  9.      if (steep){
  10.         kSwapVariable(x_start,y_start);
  11.         kSwapVariable(x_end,y_end);
  12.      }
  13.      if(x_start>x_end){
  14.         kSwapVariable(x_start,x_end);
  15.         kSwapVariable(y_start,y_end);
  16.      }
  17.      dx=x_end-x_start;
  18.      dy=abs(y_end-y_start);
  19.      err=dx/2;
  20.      if(y_start<y_end){
  21.          ystep = 1;
  22.      }
  23.      else{
  24.          ystep = -1;
  25.      }
  26.      for (;x_start<=x_end;x_start++)
  27.      {
  28.         if (steep){
  29.             TFT_DrawPixel_WithCords(y_start,x_start,color);
  30.         }
  31.         else{
  32.             TFT_DrawPixel_WithCords(x_start,y_start,color);
  33.         }
  34.         err-=dy;
  35.         if (err<0){
  36.          y_start += ystep;
  37.          err+=dx;
  38.         }
  39.      }
  40. }

Rysowanie czystego prostokąta:

  1. void Tft_DrawClearRectangle(uint16_t start_x, uint16_t start_y,
  2.                             uint16_t end_x, uint16_t end_y, uint16_t color)
  3. {
  4.     Tft_DrawLine(start_x,start_y,end_x,start_y,color);
  5.     Tft_DrawLine(end_x, start_y, end_x, end_y, color);
  6.     Tft_DrawLine(start_x, start_y, start_x, end_y, color);
  7.     Tft_DrawLine(start_x, end_y, end_x, end_y, color);
  8. }

Rysowanie prostokąta z wypełnieniem:

  1. void Tft_FillRectangle(uint16_t start_x, uint16_t start_y,
  2.                        uint16_t end_x, uint16_t end_y, uint16_t color)
  3. {
  4.     uint32_t xposition;
  5.     uint32_t yposition;
  6.    
  7.     if(start_x>end_x){
  8.         kSwapVariable(start_x,end_x);
  9.     }
  10.     if(start_y>end_y){
  11.         kSwapVariable(start_y,end_y);
  12.     }
  13.    
  14.     for(yposition=start_y;yposition<=end_y;yposition++){
  15.         for(xposition=start_x;xposition<=end_x;xposition++){
  16.                 *(__IO uint32_t*) (ILI9341_CurrentFrameBuffer + (2*(yposition*ILI9341_X + xposition)))
  17.             = color;
  18.         }
  19.   }
  20. }

Rysowanie czystego prostokąta:

  1. void Tft_DrawCircle(uint16_t x_Position, uint16_t y_Position, int radius, uint16_t color)
  2. {
  3.     int f = 1-radius;
  4.     int ddF_x=1;
  5.     int ddF_y=-2*radius;
  6.     int x = 0;
  7.     int y = radius;
  8.    
  9.     TFT_DrawPixel_WithCords(x_Position,y_Position+radius,color);
  10.     TFT_DrawPixel_WithCords(x_Position,y_Position-radius,color);
  11.     TFT_DrawPixel_WithCords(x_Position+radius,y_Position,color);
  12.     TFT_DrawPixel_WithCords(x_Position-radius,y_Position,color);
  13.     while (x<y){
  14.         if (f>=0){
  15.             y--;
  16.       ddF_y+=2;
  17.       f+=ddF_y;
  18.         }
  19.     x++;
  20.     ddF_x+=2;
  21.     f+=ddF_x;
  22.     TFT_DrawPixel_WithCords(x_Position+x,y_Position+y,color);
  23.     TFT_DrawPixel_WithCords(x_Position-x,y_Position+y,color);
  24.     TFT_DrawPixel_WithCords(x_Position+x,y_Position-y,color);
  25.     TFT_DrawPixel_WithCords(x_Position-x,y_Position-y,color);
  26.     TFT_DrawPixel_WithCords(x_Position+y,y_Position+x,color);
  27.     TFT_DrawPixel_WithCords(x_Position-y,y_Position+x,color);
  28.     TFT_DrawPixel_WithCords(x_Position+y,y_Position-x,color);
  29.     TFT_DrawPixel_WithCords(x_Position-y,y_Position-x,color);
  30.   }
  31. }

Rysowanie znaków na ekranie, czcionka musi posiadać stałą szerokość oraz wysokość. Poniżej funkcja wypisująca znak na ekranie:

  1. void Prep_Font_DrawChar(uint16_t x_position, uint16_t y_position, uint8_t sign, Prep_Font *font,
  2.                                                 uint16_t fontColor, uint16_t backColor)
  3. {
  4.   uint16_t loop_x = 0;
  5.   uint16_t loop_y = 0;
  6.   uint16_t begin_mask= 0;
  7.   uint16_t change_mask = 0;
  8.   const uint16_t *char_size;
  9.   sign -= ' ';
  10.   char_size=&font->table[sign * font->height];
  11.   if(Tft_Display_Mode==Orientation_Portrait)
  12.     {
  13.     if(font->width>8) { begin_mask=0x8000;  }
  14.         else                            {   begin_mask=0x80;        }
  15.    
  16.     for(loop_y = 0; loop_y < font->height; loop_y++)
  17.         {
  18.       change_mask=begin_mask;
  19.       Tft_SetCursor2Draw(x_position,loop_y+y_position);
  20.       for(loop_x = 0; loop_x < font->width; loop_x++)
  21.             {
  22.         if((char_size[loop_y] & change_mask) == 0x00) {
  23.           Tft_DrawPixel(backColor);
  24.         }
  25.         else {
  26.           Tft_DrawPixel(fontColor);
  27.         }
  28.         change_mask=(change_mask>>1);
  29.       }
  30.     }
  31.   }
  32.   else
  33.     {
  34.     if(font->width>8)   { begin_mask=0x8000; }
  35.         else                            { begin_mask=0x80;   }
  36.     for(loop_y = 0; loop_y < font->height; loop_y++)
  37.         {
  38.       change_mask=begin_mask;
  39.       Tft_SetCursor2Draw(x_position+font->height-loop_y,y_position);
  40.       for(loop_x = 0; loop_x < font->width; loop_x++)
  41.             {
  42.         if((char_size[loop_y] & change_mask) == 0x00) {
  43.           Tft_DrawPixel(backColor);
  44.         }
  45.         else {
  46.           Tft_DrawPixel(fontColor);
  47.         }
  48.         change_mask=(change_mask>>1);
  49.       }
  50.     }
  51.   }
  52. }

Rysowanie ciągu znaków na ekranie:

  1. void Prep_Font_DrawString(uint16_t x_position, uint16_t y_position,
  2.                                                     uint8_t *buffer, Prep_Font *font, uint16_t fontColor, uint16_t backColor)
  3. {
  4.   uint16_t writePosition;
  5.   if(Tft_Display_Mode==Orientation_Portrait)
  6.     {
  7.     writePosition=x_position;
  8.     while (*buffer != 0) {
  9.       Prep_Font_DrawChar(writePosition,y_position,*buffer,font,fontColor,backColor);
  10.       writePosition+=font->width;
  11.       buffer++;
  12.     }
  13.   }
  14.   else if(Tft_Display_Mode==Orientation_Landscape)
  15.     {
  16.     writePosition=y_position;
  17.     while (*buffer != 0) {
  18.       Prep_Font_DrawChar(x_position,writePosition,*buffer,font,fontColor,backColor);
  19.       writePosition+=font->width;
  20.       buffer++;
  21.     }
  22.   }
  23. }

Panel dotykowy:


W tym przypadku komunikacja odbywa się po interfejsie I2C (I2C3), jak właściwie dla wszystkich paneli dotykowych.

Jego podłączenie jest następujące:

  • SCL - PA8;
  • SDA - PC9;

Procedura inicjalizacyjna wygląda następująco:

  1. uint8_t TouchPad_Initialization(void)
  2. {
  3.   uint16_t touch_pad_id=0;
  4.     /* I2C3 initialization */
  5.   I2C3_Initialization();
  6.   /* Read Id */
  7.   touch_pad_id=P_Touch_ReadID();
  8.    
  9.   if(touch_pad_id!=STMPE811_ID) {
  10.         return 0;   /* Error */
  11.     }
  12.   /* Reset touch pad */
  13.   TouchPad_Reset();
  14.   /* Initialize touchpad */
  15.   TouchPad_Function_Command(IOE_ADC_FCT, ENABLE);
  16.   TouchPad_Configuration();
  17.   return 1; /* OK */
  18. }

Komunikacja poprzez interfejs I2C rozpoczyna się od wystawienia sygnału start. Jest to odpowiednia kombinacja przebiegów na linii SDA oraz SCL (do tego celu wykorzustuje się funkcje biblioteki STD). Dzięki temu informuje się układ podrzędny, że rozpocznie się transmisja danych. Kolejny etap to wysłanie adresu układu podrzędnego, z którym nastąpi komunikacja odczytu lub zapisu danych. Kierunek transmisji określa następny bit, po którym układ odpowiada bitem potwierdzenia ACK. 

W przypadku wybrania nadawania danych do układu podrzędnego, układ master wysyła kolejny bajty danych. Po każdym bajcie układ odbierający ma wysłać bit ACK. Dla komunikacji w drugą stronę to układ podrzędny wysyła kolejne bajty danych a układ nadzorujący przesyła bity ACK. Zakończenie transmisji odbywa się przez wygenerowanie sygnału STOP. 

Procedura odczytu pojedynczego bajtu przez I2C wygląda następująco:

  1. int16_t I2C3_ReadByte(uint8_t slaveAddress, uint8_t registerAddress)
  2. {
  3.   int16_t read_data=0;
  4.   uint32_t timeout=0;
  5.   /* Generate the Start Condition */
  6.   I2C_GenerateSTART(I2C3, ENABLE);
  7.   timeout=I2C3_TIMEOUT;
  8.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_SB)) {
  9.         if ((timeout--) == 0){
  10.             return(I2C3_Timeout_Service(-1));
  11.         }
  12.   }
  13.   /* Disable ACK */
  14.   I2C_AcknowledgeConfig(I2C3, DISABLE);
  15.   /* send slave adress and i2c transmission direction */
  16.   I2C_Send7bitAddress(I2C3, slaveAddress, I2C_Direction_Transmitter);
  17.   timeout=I2C3_TIMEOUT;
  18.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_ADDR)){
  19.         if ((timeout--) == 0){
  20.             return(I2C3_Timeout_Service(-1));
  21.         }
  22.   }  
  23.   /* Clear Address - flag */
  24.   I2C3->SR2;
  25.   timeout=I2C3_TIMEOUT;
  26.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_TXE)) {
  27.         if ((timeout--) == 0) {
  28.             return(I2C3_Timeout_Service(-1));
  29.         }
  30.   }  
  31.     /* Adress send */
  32.   I2C_SendData(I2C3, registerAddress);
  33.   timeout=I2C3_TIMEOUT;
  34.   while ((!I2C_GetFlagStatus(I2C3, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C3, I2C_FLAG_BTF))) {
  35.         if ((timeout--) == 0) {
  36.             return(I2C3_Timeout_Service(-1));
  37.         }
  38.   }
  39.   /* Generate the Start Condition */
  40.   I2C_GenerateSTART(I2C3, ENABLE);
  41.   timeout=I2C3_TIMEOUT;
  42.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_SB)) {
  43.         if ((timeout--) == 0) {
  44.             return(I2C3_Timeout_Service(-1));
  45.         }
  46.   }
  47.   // Slave-Adresse senden (read)
  48.   I2C_Send7bitAddress(I2C3, slaveAddress, I2C_Direction_Receiver);
  49.   timeout=I2C3_TIMEOUT;
  50.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_ADDR)) {
  51.         if ((timeout--) == 0) {
  52.             return(I2C3_Timeout_Service(-1));
  53.         }
  54.   }
  55.   /* Clear Address - flag */
  56.   I2C3->SR2;
  57.   timeout=I2C3_TIMEOUT;
  58.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_RXNE)) {
  59.         if ((timeout--) == 0) {
  60.             return(I2C3_Timeout_Service(-1));
  61.         }
  62.   }
  63.   /* Stop sequence */
  64.   I2C_GenerateSTOP(I2C3, ENABLE);
  65.   /* Read data write into variable */
  66.   read_data=(int16_t)(I2C_ReceiveData(I2C3));
  67.   /* Send ACK */
  68.   I2C_AcknowledgeConfig(I2C3, ENABLE);
  69.   return read_data;
  70. }

NACK na samym końcu informuje o zakończeniu odbierania danych.  Czyli, informuje urządzenie podrzędne, że więcej danych nie będzie już odbierane.

Procedura zapisu danych do układu podrzędnego:

  1. uint8_t I2C3_WriteByte(uint8_t slaveAddress, uint8_t registerAddress, uint8_t dataToWrite)
  2. {
  3.   int16_t status=0;
  4.   uint32_t timeout=0;
  5.   /* Generate the Start Condition */
  6.   I2C_GenerateSTART(I2C3, ENABLE);
  7.   timeout=I2C3_TIMEOUT;
  8.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_SB)) {
  9.     if(timeout!=0){
  10.             timeout--;
  11.         }
  12.         else{
  13.             return 0;
  14.         }
  15.   }
  16.   /* send slave adress and i2c transmission direction */
  17.   I2C_Send7bitAddress(I2C3, slaveAddress, I2C_Direction_Transmitter);
  18.   timeout=I2C3_TIMEOUT;
  19.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_ADDR)) {
  20.     if(timeout!=0){
  21.             timeout--;
  22.         }
  23.         else{
  24.             return 0;
  25.         }
  26.   }  
  27.   /* Clear Address - flag */
  28.   I2C3->SR2;
  29.   timeout=I2C3_TIMEOUT;
  30.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_TXE)) {
  31.     if(timeout!=0){
  32.             timeout--;
  33.         }
  34.         else{
  35.             return 0;
  36.         }
  37.   }
  38.   /* Send register value */
  39.   I2C_SendData(I2C3, registerAddress);
  40.   timeout=I2C3_TIMEOUT;
  41.   while (!I2C_GetFlagStatus(I2C3, I2C_FLAG_TXE)) {
  42.     if(timeout!=0){
  43.             timeout--;
  44.         }
  45.         else{
  46.             return 0;
  47.         }
  48.   }
  49.   /* Send data to write */
  50.   I2C_SendData(I2C3, dataToWrite);
  51.   timeout=I2C3_TIMEOUT;
  52.   while ((!I2C_GetFlagStatus(I2C3, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C3, I2C_FLAG_BTF))) {
  53.     if(timeout!=0){
  54.             timeout--;
  55.         }
  56.         else{
  57.             return 0;
  58.         }
  59.   }
  60.   /* Stop sequence */
  61.   I2C_GenerateSTOP(I2C3, ENABLE);
  62.     /* Operation OK, change status*/
  63.   status=1;
  64.   return status;
  65. }

Odczytanie danych z touchpada wykonywane jest za pomocą następującej funkcji:

  1. uint8_t TouchPad_Read_Position(void)
  2. {
  3.   uint32_t x_Different = 0;
  4.   uint32_t y_Different = 0;
  5.   uint32_t tmp_x = 0;
  6.   uint32_t tmp_y = 0;
  7.   static uint32_t x = 0;
  8.   static uint32_t y = 0;
  9.   int16_t i2c_read_data = 0;
  10.     /* Read axis data */
  11.   i2c_read_data=I2C3_ReadByte(STMPE811_I2C_ADDR, IOE_REG_TP_CTRL);
  12.    
  13.     /* Check if data was read */
  14.   if(i2c_read_data<0)   { return 0; }
  15.     /* Check touch status */
  16.   if((i2c_read_data&0x80)==0) { Touch_Data.status = TOUCH_RELEASED; }
  17.   else                        { Touch_Data.status = TOUCH_PRESSED;  }
  18.    
  19.     /* If TouchPad was clicked */
  20.   if(Touch_Data.status==TOUCH_PRESSED)
  21.   {
  22.     tmp_x = TouchPad_Read_X_Axis();
  23.     tmp_y = TouchPad_Read_Y_Axis();
  24.     x_Different = tmp_x > x? (tmp_x - x): (- tmp_x);
  25.     y_Different = tmp_y > y? (tmp_y - y): (- tmp_y);
  26.     if (x_Different + y_Different > 4)
  27.     {
  28.       x = tmp_x;
  29.       y = tmp_y;
  30.     }
  31.   }
  32.    
  33.   Touch_Data.xp = x;
  34.   Touch_Data.yp = y;
  35.   I2C3_WriteByte(STMPE811_I2C_ADDR, IOE_REG_FIFO_STA, 0x01);
  36.   I2C3_WriteByte(STMPE811_I2C_ADDR, IOE_REG_FIFO_STA, 0x00);
  37.   return 1;
  38. }

Pliki do projektu można pobrać z dysku google pod tym linkiem.