#include "project.h" #define BRIGHT 30 #define POWER 25 #define SDA 23 #define SCL 24 #define WRITE 0 #define READ 1 #define SAD (0x3C << 1) static void i2c_delay () { nrf_delay_us (1); } static void i2c_set (int c, int d) { uint32_t set = 0; uint32_t clr = 0; if (c) set |= 1 << SCL; else clr |= 1 << SCL; if (d) set |= 1 << SDA; else clr |= 1 << SDA; NRF_GPIO->OUTCLR = clr; NRF_GPIO->OUTSET = set; } static int i2c_get (void) { return ! !(NRF_GPIO->IN & (1 << SDA)); } static void i2c_start (void) { i2c_set (1, 1); i2c_delay (); i2c_set (1, 0); i2c_delay (); i2c_set (0, 0); i2c_delay (); } static void i2c_stop (void) { i2c_set (0, 0); i2c_delay (); i2c_set (1, 0); i2c_delay (); i2c_set (1, 1); i2c_delay (); } static void i2c_init (void) { NRF_GPIO->PIN_CNF[SDA] = (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_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->PIN_CNF[SCL] = (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_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->DIRSET = (1 << SDA) | (1 << SCL); i2c_set (1, 1); } static void i2c_send_byte (uint8_t v) { uint8_t c; int d; for (c = 0x80; c; c >>= 1) { d = c & v; i2c_set (0, d); i2c_delay (); i2c_set (1, d); i2c_delay (); } i2c_set (0, d); } static void i2c_handshake (int ack) { i2c_set (0, ack); i2c_delay (); i2c_set (1, ack); i2c_delay (); i2c_set (0, ack); i2c_delay (); } static void inline i2c_send_ack (void) { i2c_handshake (0); } static void inline i2c_send_nack (void) { i2c_handshake (1); } static int i2c_recv_ack (void) { int ret; i2c_set (0, 1); i2c_delay (); i2c_set (1, 1); i2c_delay (); ret = i2c_get (); i2c_set (0, 1); i2c_delay (); return ret; } static void sd_delay (void) { nrf_delay_ms (1); } static int sd_write (int dnc, uint8_t v) { int ret = 0; i2c_start (); i2c_send_byte (SAD | WRITE); ret |= i2c_recv_ack (); i2c_send_byte (dnc ? 0xc0 : 0x80); ret |= i2c_recv_ack (); i2c_send_byte (v); i2c_send_nack (); i2c_stop (); return ret; } static int sd_cmd (uint8_t c) { return sd_write (0, c); } static uint8_t cur_x; static uint8_t cur_y; static int sd_dat (uint8_t c) { cur_x++; return sd_write (1, c); } static int sd_dat0s (size_t len) { int ret = 0; i2c_start (); i2c_send_byte (SAD | WRITE); ret |= i2c_recv_ack (); i2c_send_byte (0x40); ret |= i2c_recv_ack (); while (len--) { i2c_send_byte (0); ret |= i2c_recv_ack (); cur_x++; } i2c_stop (); return ret; } static int sd_dats (uint8_t *v,size_t len) { int ret = 0; i2c_start (); i2c_send_byte (SAD | WRITE); ret |= i2c_recv_ack (); i2c_send_byte (0x40); ret |= i2c_recv_ack (); while (len--) { i2c_send_byte (*(v++)); ret |= i2c_recv_ack (); cur_x++; } i2c_stop (); return ret; } static int sd_address_mode (uint8_t m) { int ret = 0; ret |= sd_cmd (0x20); ret |= sd_cmd (m); return ret; } static int sd_cols (uint8_t s, uint8_t e) { int ret = 0; ret |= sd_cmd (0x21); ret |= sd_cmd (s); ret |= sd_cmd (e); cur_x=s; return ret; } static int sd_rows (uint8_t s, uint8_t e) { int ret = 0; ret |= sd_cmd (0x22); ret |= sd_cmd (s); ret |= sd_cmd (e); cur_y=s; return ret; } void sd_putstr(char *s,int x,int y) { static uint8_t d[8]; while (*s) { if (x!=cur_x) sd_cols (x, 127); if (y!=cur_y) sd_rows (y, 3); gt_read_8x8(*s,d,sizeof(d)); sd_dats(d,sizeof(d)); x+=8; if (x==128) { x=0; y++; } if (y==4) y=0; s++; } } void sd_cls(void) { sd_cols (0, 127); sd_rows (0, 3); sd_dat0s(128*4); } void sd_doodle (void) { static char d[12]; static int i; sd_putstr("Fishsoup",0,0); sprintf(d,"%d",i++); sd_putstr(d,0,1); } void sd_on (void) { NRF_GPIO->OUTSET = (1 << POWER) | (1 << BRIGHT); nrf_delay_ms (10); // off sd_cmd (0xae); sd_delay (); // set clock freq sd_cmd (0xd5); sd_cmd (0xa0); sd_delay (); // set multiplex ratio sd_cmd (0xa8); sd_cmd (0x1f); sd_delay (); // set display offset sd_cmd (0xd3); sd_cmd (0x00); sd_delay (); // set display start sd_cmd (0x40); sd_delay (); // set charge pump using DC/DC sd_cmd (0x8d); sd_cmd (0x14); sd_delay (); // set segment remap sd_cmd (0xa1); sd_delay (); // set com scan direction sd_cmd (0xc8); sd_delay (); // set com pins hardware config. sd_cmd (0xda); sd_cmd (0x02); sd_delay (); // set contrast sd_cmd (0x81); sd_cmd (0x8f); sd_delay (); // set precharge period using DC/DC sd_cmd (0xd9); sd_cmd (0xf1); sd_delay (); // set deselect voltage sd_cmd (0xdb); sd_cmd (0x40); sd_delay (); // set display on/off sd_cmd (0xa4); sd_delay (); // set display on sd_cmd (0xaf); sd_delay (); sd_address_mode (0); sd_cols (0, 127); sd_rows (0, 3); sd_cls(); } void sd_init (void) { i2c_init (); NRF_GPIO->PIN_CNF[POWER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->PIN_CNF[BRIGHT] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_GPIO->DIRSET = (1 << POWER) | (1 << BRIGHT); NRF_GPIO->OUTCLR = (1 << POWER) | (1 << BRIGHT); }