/******************************************************************************* * File Name : ssd1306.c * Author : lxyppc * Version : V1.0 * Date : 10-01-21 * Description : ssd1306 operations * the SSH1101A is compatible with ssd1306 *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "stm32l100c_discovery.h" #include "bsp.h" #include "ssd1306.h" #include "DrawText.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define SSD1306_PAGE_NUMBER 8 #define SSD1306_COLUMN_NUMBER 128 #define SSD1306_COLUMN_MARGIN_START 2 #define SSD1306_COLUMN_MARGIN_END 2 #define SSD1306_X_PIXEL 128 #define SSD1306_Y_PIXEL 32 /* Private macro -------------------------------------------------------------*/ #define ssd1306_Buffer (_SSD1306_Buffer + SSD1306_COLUMN_MARGIN_START) /* Private variables ---------------------------------------------------------*/ static uint8_t _SSD1306_Buffer[SSD1306_COLUMN_NUMBER*SSD1306_PAGE_NUMBER + SSD1306_COLUMN_MARGIN_START + SSD1306_COLUMN_MARGIN_END] = {0}; static uint8_t pageIndex = 0; static uint8_t iS_SSD_On = 0; static uint8_t pre_on = 0; static uint8_t curContrast = 0xCC; static uint8_t lastContrast = 0xCC; /* Private function prototypes -----------------------------------------------*/ void WriteCommand(unsigned char command); void WriteData(unsigned char data); void OnPageTransferDone(void); unsigned long ssd1306_OFF(void); unsigned long ssd1306_ON(void); unsigned char* ssd1306_GetBuffer() { return ssd1306_Buffer; } /******************************************************************************* * Function Name : WriteCommand * Description : Write command to the ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ void WriteCommand(unsigned char command) { SSD_A0_Low(); SPI_SendByte(command); SPI_Wait(); } /******************************************************************************* * Function Name : WriteData * Description : Write data to the ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ void WriteData(unsigned char data) { SSD_A0_High(); SPI_SendByte(data); SPI_Wait(); } /******************************************************************************* * Function Name : ssd1306_Init * Description : Initialize the ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ void ssd1306_Init(void) { /* Generate a reset */ SSD_Reset_Low(); uint32_t i; for(i=5000; i>1; i--) SSD_Reset_High(); WriteCommand(0xAE); WriteCommand(0xD5); WriteCommand(0x80); WriteCommand(0xA8); WriteCommand(0x1F); WriteCommand(0xD3); WriteCommand(0x00); WriteCommand(0x40 | 0x00); // line #0 WriteCommand(0x8D); WriteCommand(0x14); //10 or 14 if not externalvcc WriteCommand(0x20); WriteCommand(0x00); WriteCommand(0xA0 | 0x1); // segremap WriteCommand(0xC8); // comscandep WriteCommand(0xDA); // setcompins WriteCommand(0x02); WriteCommand(0x81); // contrast WriteCommand(0x0F); // contrast value. 8f is a good one. WriteCommand(0xD9); WriteCommand(0xF1); //22 or F1 if not externalvcc WriteCommand(0xDB); WriteCommand(0x40); WriteCommand(0xA4); // dispalyallon_resume WriteCommand(0xA6); // normaldisplay WriteCommand(0xAF); // display on // Clear buffer // for(i=0;i<900;i++) // ssd1306_Buffer[i] = 0; /************************************************* // ssd1306 Initialization Command *************************************************/ /* // Lower Column Address WriteCommand(0x00); // Set Lower Column Address GPIO_SetBits(GPIOA,GPIO_Pin_15);//turn on status LED // High Column Address WriteCommand(0x10); // Set Higher Column Address // Display Start Line WriteCommand(0x40); // Set Display Start Line #ifdef DEBUG_BOARD curContrast = lastContrast = 0x30; #else curContrast = lastContrast = 0xCF; #endif // Contrast Control Register WriteCommand(0x81); // Set Contrast Control WriteCommand(lastContrast); // 0 ~ 255 0x1f // Re-map WriteCommand(0xA1); // [A0]:column address 0 is map to SEG0 , [A1]: columnaddress 131 is map to SEG0 // Entire Display ON/OFF WriteCommand(0xA4); // A4=ON // Normal or Inverse Display WriteCommand(0XA6); // Normal Display // Multiplex Ratio WriteCommand(0xA8); // Set Multiplex Ratio WriteCommand(0x3f); // Set to 36 Mux // Set DC-DC WriteCommand(0xAD); // Set DC-DC WriteCommand(0x8B); // 8B=ON, 8A=Off // Display ON/OFF WriteCommand(0xAE); // AF=ON , AE=OFF // Display Offset WriteCommand(0xD3); // Set Display Offset WriteCommand(0x00); // No offset // Display Clock Divide WriteCommand(0xD5); // Set Clock Divide WriteCommand(0x20); // Set to 80Hz // Area Color Mode WriteCommand(0xD8); // Set Area Color On or Off WriteCommand(0x00); // Mono Mode // COM Pins Hardware Configuration WriteCommand(0xDA); // Set Pins HardwareConfiguration WriteCommand(0x12); // VCOMH WriteCommand(0xDB); // Set VCOMH WriteCommand(0x00); // VP WriteCommand(0xD9); // Set VP WriteCommand(0x22); // P1=2 , P2=2 // Set Common output scan direction WriteCommand(0xc8);// Set COM scan direction // For SSD1306 Set the address mode WriteCommand(0x20);// Set address mode WriteCommand(0x00);// Set address mode horizontal // Set the page start address WriteCommand(0xb0); WriteCommand(0x00); WriteCommand(0x10); // Turn on the controller pre_on = ssd1306_ON(); // // Set Charge pump // WriteCommand(0x8D); // Set Charge pump // WriteCommand(0x14); // 0x14=ON, 0x10=Off // // // Turn on the display // WriteCommand(0xaf); */ } void ssd1306_block_write(void) { // Set col start addr to 0 WriteCommand(0x21); WriteCommand(0x00); // Set col end addr to width - 1 WriteCommand(127); // Set page addr WriteCommand(0x22); WriteCommand(0x00); // start page addr WriteCommand(4); // end page addr (height / 8) uint32_t i = 0; for(i=0;i<512;i++) WriteData(ssd1306_Buffer[i]); // for(i=0;i<512;i++) // * * * * // WriteData(0b00000011); } /******************************************************************************* * Function Name : ssd1306_TurnOff * Description : Turn off the ssd1306 controller * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_TurnOff(void) { pre_on = 0; return iS_SSD_On; } /******************************************************************************* * Function Name : ssd1306_TurnOn * Description : Turn off the ssd1306 controller * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_TurnOn(void) { pre_on = 1; return iS_SSD_On; } /******************************************************************************* * Function Name : ssd1306_SetContrast * Description : Set the ssd1306 contrast * Input : None * Output : None * Return : None *******************************************************************************/ unsigned char ssd1306_SetContrast(unsigned char contrast) { curContrast = contrast; return lastContrast; } /******************************************************************************* * Function Name : ssd1306_GetContrast * Description : Get the ssd1306 contrast * Input : None * Output : None * Return : None *******************************************************************************/ unsigned char ssd1306_GetContrast() { return lastContrast; } /******************************************************************************* * Function Name : ssd1306_OFF * Description : Turn off the ssd1306 controller * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_OFF(void) { if(iS_SSD_On){ #ifdef DEBUG_UI uint32_t i = 0; for(i=0;iCCR &= ((uint32_t)0xFFFFFFFE); DMA1_Channel5->CNDTR = ssd1306_COLUMN_NUMBER+SSD1306_COLUMN_MARGIN_START + SSD1306_COLUMN_MARGIN_END; DMA1_Channel5->CMAR = (uint32_t)(ssd1306_Buffer+SSD1306_COLUMN_NUMBER*pageIndex - SSD1306_COLUMN_MARGIN_START); DMA_SSD_1306->CCR |= ((uint32_t)0x00000001); pageIndex++; #else SSD_A0_High(); DMA_SSD_1306->CCR &= ((uint32_t)0xFFFFFFFE); DMA_SSD_1306->CNDTR = SSD1306_COLUMN_NUMBER*SSD1306_PAGE_NUMBER;//+SSD1306_COLUMN_MARGIN_START + SSD1306_COLUMN_MARGIN_END; DMA_SSD_1306->CMAR = (uint32_t)(ssd1306_Buffer);//+SSD1306_COLUMN_NUMBER*pageIndex); //DMA_Cmd(DMA_SSD_1306, ENABLE); DMA_SSD_1306->CCR |= ((uint32_t)0x00000001); // pageIndex++; pageIndex = SSD1306_PAGE_NUMBER; #endif } /******************************************************************************* * Function Name : DMA1_Channel5_IRQHandler * Description : This function handles DMA1 Channel 5 interrupt request. * Input : None * Output : None * Return : None *******************************************************************************/ void DMA_Handler_SSD_1306(void) //DMA1_Channel5_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC5)){ DMA_ClearITPendingBit(DMA1_IT_GL5); OnPageTransferDone(); } } /******************************************************************************* * Function Name : StartPageTransfer * Description : Start a new page transfer * Input : None * Output : None * Return : None *******************************************************************************/ void StartPageTransfer(void) { pageIndex = 0; if(pre_on){ if(iS_SSD_On == 0){ pre_on = ssd1306_ON(); } }else{ if(iS_SSD_On){ pre_on = ssd1306_OFF(); } } if( curContrast != lastContrast ){ lastContrast = curContrast; WriteCommand(0x81); /* Set Contrast Control */ WriteCommand(lastContrast); /* 0 ~ 255 0x1f*/ } if(iS_SSD_On){ OnPageTransferDone(); } } /******************************************************************************* Display related functions ******************************************************************************/ /******************************************************************************* * Function Name : ssd1306_DrawBlock * Description : Draw a block with specify data to ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_DrawBlock( Pos_t x, Pos_t y, Pos_t cx, Pos_t cy, const unsigned char* data) { if(x >= SSD1306_X_PIXEL)return 0; if(y >= SSD1306_Y_PIXEL)return 0; if(x+cx > SSD1306_X_PIXEL ) cx = SSD1306_X_PIXEL - x ; if(y+cy > SSD1306_Y_PIXEL ) cy = SSD1306_Y_PIXEL - y ; unsigned char* pStart = ssd1306_Buffer + (y/8)*SSD1306_COLUMN_NUMBER + x; unsigned char offset1 = y%8; unsigned char offset2 = (cy+y)%8; if(data){ unsigned char mask1 = (1<>=8; } if(offset2){ tmp |= ((((unsigned short)data[j*cx])<>=8; // if(j == (cy/8)-1){ // // Last line // *(pStart + (j+1)*ssd1306_COLUMN_NUMBER + i + x) &= ~mask; // *(pStart + (j+1)*ssd1306_COLUMN_NUMBER + i + x) |= tmp; // } // } // } // } return 0; } /******************************************************************************* * Function Name : ssd1306_DrawPoint * Description : Draw a point with specify data to ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_DrawPoint( Pos_t x, Pos_t y, Color_t color) { if(x >= SSD1306_X_PIXEL)return 0; if(y >= SSD1306_Y_PIXEL)return 0; unsigned char* pStart = ssd1306_Buffer + (y/8)*SSD1306_COLUMN_NUMBER + x; unsigned char mask = 1<<(y%8); if(color){ *pStart |= mask; }else{ *pStart &= ~mask; } return 0; } /******************************************************************************* * Function Name : ssd1306_ReadPoint * Description : Read a point from ssd1306 * Input : None * Output : None * Return : None *******************************************************************************/ unsigned long ssd1306_ReadPoint( Pos_t x, Pos_t y) { unsigned char* pStart = ssd1306_Buffer + (y/8)*SSD1306_COLUMN_NUMBER + x; unsigned char mask = 1<<(y%8); return *pStart&mask ? 1 : 0; } /******************************************************************************* * Function Name : ssd1306_ClearScreen * Description : Clear the screen contents * Input : None * Output : None * Return : None *******************************************************************************/ void ssd1306_FillScreen(Color_t color) { unsigned char mask = color ? 0xFF : 0; unsigned long i = 0; for(i=0;i= font.u8FirstChar) && (c <= font.u8LastChar)) { // Retrieve appropriate columns from font data for (col = 0; col < font.u8Width; col++) { column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character } } else { // Requested character is not available in this font ... send a space instead for (col = 0; col < font.u8Width; col++) { column[col] = 0xFF; // Send solid space } } // Render each column uint16_t xoffset, yoffset; for (xoffset = 0; xoffset < font.u8Width; xoffset++) { for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++) { uint8_t bit = 0x00; bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white) if (bit) { ssd1306_DrawPixel(x + xoffset, y + yoffset, 1); } } } } ssd1306_DrawString(uint8_t x, uint8_t y, const char *text, struct FONT_DEF font) { uint8_t l; for (l = 0; l < strlen(text); l++) { ssd1306DrawChar(x + (l * (font.u8Width + 1)), y, text[l], font); } } */