#include #include #include "nrf.h" #include "nrf_delay.h" #include "nrf_gpio.h" #define I2C_SDA_PIN 6 #define I2C_SCL_PIN 7 #define I2C_RES_PIN 8 /*lint -e415 -e845 -save "Out of bounds access" */ #define TWI_SDA_STANDARD0_NODRIVE1() do { \ NRF_GPIO->PIN_CNF[I2C_SDA_PIN] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ |(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ |(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \ |(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ |(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \ } while (0) /*!< Configures SDA pin to Standard-0, No-drive 1 */ #define TWI_SCL_STANDARD0_NODRIVE1() do { \ NRF_GPIO->PIN_CNF[I2C_SCL_PIN] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \ |(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \ |(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \ |(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \ |(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \ } while (0) /*!< Configures SCL pin to Standard-0, No-drive 1 */ /* These macros are needed to see if the slave is stuck and we as master send dummy clock cycles to end its wait */ /*lint -e717 -save "Suppress do {} while (0) for these macros" */ /*lint ++flb "Enter library region" */ #define I2C_SCL_HIGH() do { NRF_GPIO->OUTSET = (1UL << I2C_SCL_PIN); } while(0) /*!< Pulls SCL line high */ #define I2C_SCL_LOW() do { NRF_GPIO->OUTCLR = (1UL << I2C_SCL_PIN); } while(0) /*!< Pulls SCL line low */ #define I2C_SDA_HIGH() do { NRF_GPIO->OUTSET = (1UL << I2C_SDA_PIN); } while(0) /*!< Pulls SDA line high */ #define I2C_SDA_LOW() do { NRF_GPIO->OUTCLR = (1UL << I2C_SDA_PIN); } while(0) /*!< Pulls SDA line low */ #define I2C_RES_HIGH() do { NRF_GPIO->OUTSET = (1UL << I2C_RES_PIN); } while(0) /*!< Pulls RES line high */ #define I2C_RES_LOW() do { NRF_GPIO->OUTCLR = (1UL << I2C_RES_PIN); } while(0) /*!< Pulls RES line low */ #define I2C_SDA_INPUT() do { NRF_GPIO->DIRCLR = (1UL << I2C_SDA_PIN); } while(0) /*!< Configures SDA pin as input */ #define I2C_SDA_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << I2C_SDA_PIN); } while(0) /*!< Configures SDA pin as output */ #define I2C_SCL_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << I2C_SCL_PIN); } while(0) /*!< Configures SCL pin as output */ #define I2C_RES_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << I2C_RES_PIN); } while(0) /*!< Configures RES pin as output */ #define I2C_SDA_READ() ((NRF_GPIO->IN >> I2C_SDA_PIN) & 0x1UL) /*!< Reads current state of SDA */ #define I2C_SCL_READ() ((NRF_GPIO->IN >> I2C_SCL_PIN) & 0x1UL) /*!< Reads current state of SCL */ #define I2C_Device_Address 0x78 // 0111 1000 SA0 ¿Í R/W# µÑ´Ù 0 #define TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE (0UL) //!< Unit is number of empty loops. Timeout for SMBus devices is 35 ms. Set to zero to disable slave timeout altogether. static uint8_t OLED_Font6x8 [] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // ! 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // " 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // # 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $ 0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // % 0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // & 0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // ' 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // ( 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // ) 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // * 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // + 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // , 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // - 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // . 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // / 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // : 0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ; 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // < 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // = 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // > 0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ? 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @ 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R 0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X 0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y 0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [ 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ] 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _ 0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // ' 0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b 0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d 0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r 0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines }; int ACK = 0; static bool twi_master_wait_while_scl_low(void) { #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 uint32_t volatile timeout_counter = TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE; #endif // Pull SCL high just in case if something left it low I2C_SCL_HIGH(); nrf_delay_us(4); while (I2C_SCL_READ() == 0) { // If SCL is low, one of the slaves is busy and we must wait #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0 if (timeout_counter-- == 0) { // If timeout_detected, return false return false; } #endif } return true; } void Start_Condition() { I2C_SDA_HIGH(); //nrf_delay_us(1); if (!twi_master_wait_while_scl_low()){}; I2C_SDA_LOW(); //nrf_delay_us(1); I2C_SCL_LOW(); //nrf_delay_us(1); } void Stop_Condition() { I2C_SDA_LOW(); //nrf_delay_us(1); if (!twi_master_wait_while_scl_low()){}; //I2C_SCL_HIGH(); //nrf_delay_us(1); I2C_SDA_HIGH(); //nrf_delay_us(1); } void Send_Byte(uint_fast8_t byte) { I2C_SDA_OUTPUT(); for(uint_fast8_t i = 0x80; i != 0; i >>= 1) // ÇÑ ºñÆ®¾¿ ¹Ð¾î°¡¸é¼­ ºñÆ® °Ë»ç¸¦ ½Ç½ÃÇÑ´Ù. { I2C_SCL_LOW(); nrf_delay_us(4); if(byte & i) I2C_SDA_HIGH(); // µ¥ÀÌÅÍ°¡ ÀÖÀ¸¸é HIGH ¾øÀ¸¸é LOW else I2C_SDA_LOW(); if(twi_master_wait_while_scl_low()) break; } // Finish last data bit by pulling SCL low I2C_SCL_LOW(); nrf_delay_us(4); /** @snippet [TWI SW master write] */ // Configure TWI_SDA pin as input for receiving the ACK bit I2C_SDA_INPUT(); // Give some time for the slave to load the ACK bit on the line nrf_delay_us(4); if(twi_master_wait_while_scl_low()) {}; // Read ACK/NACK. NACK == 1, ACK == 0 ACK = !(I2C_SDA_READ()); I2C_SCL_LOW(); nrf_delay_us(4); I2C_SDA_OUTPUT(); } void Send_Command(uint8_t command) { Start_Condition(); Send_Byte(I2C_Device_Address); Send_Byte(0x00); //Write command [co, D/C, Control byte] = 0x00, D/C = 0 Send_Byte(command); Stop_Condition(); } /* void Send_Data(uint8_t * Data) { Start_Condition(); Send_Byte(I2C_Device_Address); Send_Byte(0x40); //Write Data [co, D/C, Control byte] = 0x40, D/C = 1 Send_Byte(*Data); Stop_Condition(); } */ void Send_Data_Start() { Start_Condition(); Send_Byte(I2C_Device_Address); Send_Byte(0x40); //Write Data [co, D/C, Control byte] = 0x40, D/C = 1 } void Send_Data_Stop() { Stop_Condition(); } void I2C_Init() { // Configure both pins to output Standard 0, No-drive (open-drain) 1 TWI_SDA_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ TWI_SCL_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */ // Configure SCL as output I2C_SCL_HIGH(); I2C_SCL_OUTPUT(); // Configure SDA as output I2C_SDA_HIGH(); I2C_SDA_OUTPUT(); } void SSD1306_Init() { nrf_delay_us(3) ; // Power On Çϱâ À§Çؼ­ RES H->L->H·Î ÇØÁÖ¸ç ½ÃÄý½º ±×·¡ÇÁ¸¦ º¸¸é »çÀÌ ½Ã°£Àº ÃÖ¼Ò 3us ÇÊ¿äÇÏ´Ù. I2C_RES_OUTPUT(); I2C_RES_HIGH(); nrf_delay_us(3) ; I2C_RES_LOW(); nrf_delay_us(3) ; I2C_RES_HIGH(); nrf_delay_ms(100); //¸í·ÉÀ» º¸³½´Ù. Send_Command(0xAE); // Display off Send_Command(0xD5); // Set Display Clock Div Send_Command(0x80); // the suggested ratio Send_Command(0xA8); // Set Multiplex Send_Command(0x3F); Send_Command(0xD3); // Set Display Offset Send_Command(0x00); // no offset Send_Command(0x40); // Set Start Line Send_Command(0x8D); // Charge Pump Send_Command(0x14); // Pump On Send_Command(0x20); // Memory Mode Send_Command(0x00); // À̰͵µ È®ÀÎ Send_Command(0xA1); // Set Seg ReMap_1 Send_Command(0xC8); // Com Scan Dec(Nor) Send_Command(0xDA); // Set Com Pins Send_Command(0x12); Send_Command(0x81); // Set Contrast Send_Command(0xCF); // ´Ù½Ã È®ÀÎ(FF?) Send_Command(0xD9); // Set PreCharge Send_Command(0xF1); Send_Command(0xDB); // Set VCom Detect Send_Command(0x40); Send_Command(0xA4); // Display All On Resume Send_Command(0xA6); // Normal Display //Send_Command(0x20); // Memory Addressing //Send_Command(0x00); Send_Command(0xAF); // Display On } void Display_Set_Pos(uint8_t x, uint8_t y) { Start_Condition(); Send_Byte(I2C_Device_Address); //Slave address,SA0=0 Send_Byte(0x00); //write command Send_Byte(0xb0+y); Send_Byte(((x&0xf0)>>4)|0x10); // |0x10 Send_Byte((x&0x0f)|0x01); // |0x01 Stop_Condition(); } void Send_Font_6x8(uint8_t x, uint8_t y, const char ch[]) { uint8_t c,i,j=0; while(ch[j] != '\0') { c = ch[j] - 32; if(x>126) { x=0; y++; } Display_Set_Pos(x,y); Send_Data_Start(); for(i=0;i<6;i++) { Send_Byte(OLED_Font6x8[c*6+i]); } Send_Data_Stop(); x += 6; j++; } } int main(void) { char Data_Buffer[] = {"c"}; SystemInit(); I2C_Init(); SSD1306_Init(); while(true) { Send_Font_6x8(10,10,Data_Buffer); } } /** @} */