Skip to content

Commit e02859b

Browse files
author
harbaum
committed
Add output driver chip detect sketch
1 parent 265e2e9 commit e02859b

3 files changed

Lines changed: 281 additions & 0 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// ChipDetect.ino
2+
//
3+
// Detect the output driver chip installed on the ftDuino
4+
5+
#include <SPI.h>
6+
#include <Adafruit_GFX.h>
7+
#include "FtduinoDisplay.h"
8+
9+
FtduinoDisplay display;
10+
11+
#define CHIP_UNKNOWN 0
12+
#define CHIP_MC33879 1
13+
#define CHIP_TLE94108 2
14+
#define CHIP_DRV8908 3
15+
16+
int chip = CHIP_UNKNOWN;
17+
18+
const String names[] = {
19+
"UNKNOWN", "MC33879", "TLE94108", "DRV8908"
20+
};
21+
22+
void print_centered(char size, char y, String str) {
23+
display.setTextSize(size);
24+
display.setCursor(64-(str.length()*3*size), 8*y);
25+
display.print(str);
26+
}
27+
28+
void driver_prepare() {
29+
// start the SPI library:
30+
SPI.begin();
31+
SPI.beginTransaction(SPISettings(250000, MSBFIRST, SPI_MODE1));
32+
33+
// /CS is PB.0
34+
DDRB |= (1<<0);
35+
36+
// For MC33879 PB.7 is the PWM input of the IN6 of O2. We don't use that
37+
// feature in this driver, so it's just pulled down. This is also ok with
38+
// the TLE94108 which has this pin grounded. For the DRV8908 this is the
39+
// fault output which is an open collector output. Grounding that is also
40+
// not a problem.
41+
DDRB |= (1<<7);
42+
PORTB &= ~(1<<7); // no PWM on IN6
43+
44+
// get chip out of sleep mode
45+
DDRE |= (1<<6);
46+
PORTE |= (1<<6); // not in sleep mode
47+
}
48+
49+
uint8_t transfer(uint8_t val) {
50+
delay(1);
51+
PORTB &= ~(1<<0);
52+
uint8_t r = SPI.transfer(val);
53+
PORTB |= (1<<0);
54+
55+
return r;
56+
}
57+
58+
int probe() {
59+
transfer(0x00); // first transfer will cause a SPI error on TLE94108
60+
uint8_t r = transfer(0x00);
61+
62+
// test for MC33879: This simply returns 0x00
63+
if(!r) return CHIP_MC33879;
64+
65+
// test for TLE94108: ignore undervoltage bit 4, all other bits should be
66+
// zero except bit 0 which reports a SPI error as 0x00 is not a valid request
67+
if((r & ~4) == 0x01) return CHIP_TLE94108;
68+
69+
// test for drv8908: The two upper bits are always 1, ignore undervoltage
70+
// bit 4, all other bits should be zero
71+
if((r & ~4) == 0xc0) return CHIP_DRV8908;
72+
73+
return CHIP_UNKNOWN;
74+
}
75+
76+
void setup() {
77+
Serial.begin(115200);
78+
79+
driver_prepare();
80+
81+
// wait a second for USB
82+
uint32_t to = millis();
83+
while(!Serial && millis()-to < 2000);
84+
85+
Serial.println("ftDuino output driver chip detector");
86+
87+
// LED initialisieren
88+
pinMode(LED_BUILTIN, OUTPUT);
89+
90+
display.setTextColor(WHITE);
91+
92+
print_centered(1, 0, "Driver Detection");
93+
94+
chip = probe();
95+
Serial.print("Chip: ");
96+
Serial.println(names[chip]);
97+
98+
print_centered(2, 2, names[chip]);
99+
100+
display.display();
101+
}
102+
103+
void blink(int len) {
104+
digitalWrite(LED_BUILTIN, HIGH);
105+
delay(len);
106+
digitalWrite(LED_BUILTIN, LOW);
107+
delay(100);
108+
}
109+
110+
void loop() {
111+
blink(250); // long
112+
113+
// blink pattern if no display is connected
114+
// n * short
115+
for(char i=0;i<chip;i++)
116+
blink(100);
117+
118+
delay(1000);
119+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "FtduinoDisplay.h"
2+
3+
#define OLED_INIT
4+
5+
#ifdef OLED_INIT
6+
static const uint8_t PROGMEM lcdBootProgram[] = {
7+
// Cmd mode
8+
0x00,
9+
10+
// Display Off
11+
0xAE,
12+
13+
// Set Display Clock Divisor v = 0xF0
14+
// default is 0x80
15+
0xD5, 0xF0,
16+
17+
// Set Multiplex Ratio v = HEIGHT-1
18+
0xA8, FTDDSP_HEIGHT-1,
19+
20+
// Set Display Offset v = 0
21+
0xD3, 0x00,
22+
23+
// Set Start Line (0)
24+
0x40,
25+
26+
// Charge Pump Setting v = enable (0x14)
27+
// default is disabled
28+
0x8D, 0x14,
29+
30+
// Set Segment Re-map (A0) | (b0001)
31+
// default is (b0000)
32+
0xA1,
33+
34+
// Set COM Output Scan Direction
35+
0xC8,
36+
37+
// Set COM Pins v
38+
0xDA, 0x02,
39+
40+
// Set Contrast v = 0x8F
41+
0x81, 0x8F,
42+
43+
// Set Precharge = 0xF1
44+
0xD9, 0xF1,
45+
46+
// Set VCom Detect
47+
0xDB, 0x40,
48+
49+
// Entire Display ON
50+
0xA4,
51+
52+
// Set normal/inverse display
53+
0xA6,
54+
55+
// Display On
56+
0xAF,
57+
58+
// set display mode = horizontal addressing mode (0x00)
59+
0x20, 0x00,
60+
61+
// set col address range
62+
0x21, 0x00, FTDDSP_WIDTH-1,
63+
64+
// set page address range
65+
0x22, 0x00, 0x03
66+
};
67+
#endif
68+
69+
uint8_t FtduinoDisplay::i2c_send_byte(uint8_t data) {
70+
uint8_t timeout = 0;
71+
TWDR = data;
72+
TWCR = _BV(TWINT) | _BV(TWEN);
73+
while(( !(TWCR & _BV(TWINT))) && ++timeout);
74+
return timeout;
75+
}
76+
77+
uint8_t FtduinoDisplay::i2c_start(void) {
78+
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
79+
while( !(TWCR & _BV(TWINT)));
80+
81+
return i2c_send_byte(0x3C<<1); // OLED I2C address
82+
}
83+
84+
void FtduinoDisplay::i2c_stop(void) {
85+
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO);
86+
while( (TWCR & _BV(TWSTO)));
87+
}
88+
89+
void FtduinoDisplay::i2c_send(uint16_t num, uint8_t *p) {
90+
while(num--)
91+
i2c_send_byte(*p++);
92+
}
93+
94+
void FtduinoDisplay::i2c_send(uint16_t num, const uint8_t *p) {
95+
while(num--)
96+
i2c_send_byte(pgm_read_byte(p++));
97+
}
98+
99+
FtduinoDisplay::FtduinoDisplay(void) :
100+
Adafruit_GFX(FTDDSP_WIDTH, FTDDSP_HEIGHT) {
101+
#ifdef OLED_INIT
102+
// constructor
103+
TWSR = 0;
104+
TWBR = F_CPU/(2*400000)-8;
105+
106+
if(!i2c_start()) return;
107+
i2c_send(sizeof(lcdBootProgram), lcdBootProgram);
108+
i2c_stop();
109+
#endif
110+
TWBR = 1;
111+
memset(buffer, 0, sizeof(buffer));
112+
}
113+
114+
// the most basic function, set a single pixel
115+
void FtduinoDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
116+
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
117+
return;
118+
119+
// x is which column
120+
switch (color) {
121+
case WHITE: buffer[x+ (y/8)*FTDDSP_WIDTH] |= (1 << (y&7)); break;
122+
case BLACK: buffer[x+ (y/8)*FTDDSP_WIDTH] &= ~(1 << (y&7)); break;
123+
case INVERSE: buffer[x+ (y/8)*FTDDSP_WIDTH] ^= (1 << (y&7)); break;
124+
}
125+
}
126+
127+
void FtduinoDisplay::display(void) {
128+
i2c_start();
129+
i2c_send_byte(0x40); // data
130+
i2c_send(512, buffer);
131+
i2c_stop();
132+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef _FTDUINO_DISPLAY_H_
2+
#define _FTDIUNO_DISPLAY_H_
3+
4+
#include <Adafruit_GFX.h>
5+
6+
#define FTDDSP_WIDTH 128
7+
#define FTDDSP_HEIGHT 32
8+
9+
#define BLACK 0
10+
#define WHITE 1
11+
#define INVERSE 2
12+
13+
class FtduinoDisplay : public Adafruit_GFX {
14+
public:
15+
FtduinoDisplay();
16+
void drawPixel(int16_t x, int16_t y, uint16_t color);
17+
void display();
18+
19+
private:
20+
uint8_t i2c_send_byte(uint8_t data);
21+
uint8_t i2c_start(void);
22+
void i2c_stop(void);
23+
void i2c_send(uint16_t num, uint8_t *p);
24+
void i2c_send(uint16_t num, const uint8_t *p);
25+
26+
uint8_t buffer[FTDDSP_HEIGHT * FTDDSP_WIDTH / 8];
27+
};
28+
29+
30+
#endif // _FTDIUNO_DISPLAY_H_

0 commit comments

Comments
 (0)