Getting generic Arduino boards with CH340G chips to work with OS X 10.11 El Capitan

This evening my project was to get a generic Arduino Mega board that Baz ordered from China working with my MacBook Air running El Capitan. Plugging the board in and launching the Arduino IDE yielded nothing in Tools -> Port.

After a lot of searching, it seems like the problem is the USB to serial chip used on this Arduino clone is a CH340G chip, not the usual FTDI chip that ships with official Arduino boards.  This chip handles the communication between the USB connection and the serial interface to the Arduino board. Unfortunately it is not recognised by OSX.

ch340g-arduino
Note the CH340G chip on the top left

There is a driver online, provided by a Chinese manufacturer, which provides a kernel extension (ktext) to recognise the chip. Unfortunately the ktext is not signed.  Previous versions of OS X would let you disable the requirement for ktext signing by typing a sudo command in Terminal, but with El Capitan you have to boot to the recovery partition to disable the System Integrity Protection (SIP) which prevents unsigned ktexts from running.

Disabling SIP is a really bad idea! Fortunately there is a company called CodeBender which produces a plugin for Firefox and Chrome that gives you an in-browser Arduino IDE. They have released a signed ktext for the CH340G chips so you don’t have to mess around with the security settings on your Mac. It’s not possible to download the drivers directly, but if you install their add-on in Firefox or Chrome (doesn’t work in Safari), you’ll get a link to install the drivers. When you next launch the Arduino IDE, you’ll see your generic Arduino listed in the Tools > Port menu.

Here’s the link to install the add-on.

 

Using the KYX-5461AS 4-digit 7-segment LED display with Arduino

This part came with an Arduino starter kit bought in preparation for the first Limerick Hackathon. It was really difficult to find information on the web about this part.

KYX-5461AS

The part description said that this was a common Anode display, which is wrong, it’s a common cathode. This means that you need to connect resistors to the pins driving each digit (rather than each segment pin with a common anode) to avoid blowing the LEDs.

Here’s the pinout:

1 Segment E
2 Segment D
3 Decimal point
4 Segment C
5 Segment G
6 Digit 4
7 Segment B
8 Digit 3
9 Digit 2
10 Segment F
11 Segment A
12 Digit 1

Segment labels (I can never seem to remember these):
7 segment display labeled
So to display a number 1 on the third digit you would power pins 4, 7 and 8.

To display numbers on all 4 digits, you need to introduce a delay in between powering each digit in your loop() block.

To test I rigged up a LM35 temperature sensor to an Arduino board and displayed the temperature on the display. The display was a bit dim as the lowest resistors I had were 1kΩ which were too high.

temperature-sensor

Here’s the quick code I wrote to read the temperature from a LM35 temperature sensor and display it on the KYX-5461AS display.

//reading temperature and outputting to display
int sensorPin = 0;

//display pins
int segA = 5;
int segB = 13;
int segC = 10;

int segD = 8;
int segE = 7;
int segF = 4;
int segG = 11;
int segPt = 9;

int d1 = 6;

int d2 = 3;
int d3 = 2;
int d4 = 12;

int delayTime = 900;

int counter = 0;

float temperature = 77.7;

void setup() {
// put your setup code here, to run once:
//start serial communications
Serial.begin(9600);

//set up outputs
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
pinMode(9, OUTPUT);
pinMode(8, OUTPUT);
pinMode(7, OUTPUT);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);
pinMode(4, OUTPUT);
pinMode(3, OUTPUT);
pinMode(2, OUTPUT);
pinMode(13, OUTPUT);
pinMode(0,INPUT);
delay(1000);
}

void loop() {

// put your main code here, to run repeatedly:

//only read temp every 100 cycles
if(counter%500 == 0)
{
// read the pin
int reading = analogRead(sensorPin);
//convert reading to volts
float volts = (reading * 5.0);
volts /= 1024.0;
// Serial.print(volts);
// Serial.println(" v");
temperature = volts * 100.0;
Serial.print(temperature);
Serial.println(" degrees Celsius");

//test output to display
// allHigh();
//reset our counter
counter = 0;
}

counter ++;

selectDigit(1);
sendDigit(tens(temperature));
delayMicroseconds(delayTime);

digitalWrite(d1, HIGH);
selectDigit(2);
sendDigit(ones(temperature));
point();
delayMicroseconds(delayTime);

digitalWrite(d2, HIGH);
selectDigit(3);
sendDigit(points(temperature));
delayMicroseconds(delayTime);
//turn point off

digitalWrite(d3, HIGH);
digitalWrite(segPt,HIGH);
selectDigit(4);
cee();
delayMicroseconds(delayTime);
digitalWrite(d4, HIGH);



}

void allLow() {

digitalWrite( 13, LOW); // A
digitalWrite( 2, LOW); // B
digitalWrite( 3, LOW); // C
digitalWrite(4, LOW); // D
digitalWrite(5, LOW); // E
digitalWrite( 6, LOW); // F
digitalWrite( 7, LOW); // G
digitalWrite(8, LOW); //point
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);

}

void allHigh() {

digitalWrite( 13, HIGH); // A
digitalWrite( 2, HIGH); // B
digitalWrite( 3, HIGH); // C
digitalWrite(4, HIGH); // D
digitalWrite(5, HIGH); // E
digitalWrite( 6, HIGH); // F
digitalWrite( 7, HIGH); // G
digitalWrite(8, HIGH); //point
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
digitalWrite(11, HIGH);
digitalWrite(12, HIGH);

}

void one()
{
digitalWrite(segA, LOW);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, LOW);
digitalWrite(segPt, LOW);

}
void two()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, LOW);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, LOW);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void three()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void four()
{
digitalWrite(segA, LOW);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void five()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, LOW);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void six()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, LOW);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void seven()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, LOW);
digitalWrite(segE, LOW);
digitalWrite(segF, LOW);
digitalWrite(segG, LOW);
digitalWrite(segPt, LOW);

}
void eight()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void nine()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, LOW);
digitalWrite(segF, HIGH);
digitalWrite(segG, HIGH);
digitalWrite(segPt, LOW);

}
void zero()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, HIGH);
digitalWrite(segC, HIGH);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, LOW);
digitalWrite(segPt, LOW);

}

void cee()
{
digitalWrite(segA, HIGH);
digitalWrite(segB, LOW);
digitalWrite(segC, LOW);
digitalWrite(segD, HIGH);
digitalWrite(segE, HIGH);
digitalWrite(segF, HIGH);
digitalWrite(segG, LOW);
digitalWrite(segPt, LOW);
}

void point()
{
digitalWrite(segPt, HIGH);
}

void selectDigit(int d)
{
/*
digitalWrite(d1,HIGH);

digitalWrite(d2,HIGH);
digitalWrite(d3,HIGH);
digitalWrite(d4,HIGH);
*/

switch (d)
{
case 1:
digitalWrite(d1, LOW);
break;
case 2:
digitalWrite(d2, LOW);
break;
case 3:
digitalWrite(d3, LOW);
break;
default:
digitalWrite(d4, LOW);
break;
}
}

void sendDigit(int x)
{
switch(x)
{
case 1:
one();
break;
case 2:
two();
break;
case 3:
three();
break;
case 4:
four();
break;
case 5:
five();
break;
case 6:
six();
break;
case 7:
seven();
break;
case 8:
eight();
break;
case 9:
nine();
break;
case 10:
cee();
break;
default:
zero();
break;
}
}

int tens(float x)
{
float divided = x/10.0;
return (int)divided;
}

int ones(float x)
{
float divided = x - (10.0 * tens(x));
// Serial.print(divided);
// Serial.println(" ***ones***");
return (int)divided;
}

int points(float x)
{
float divided = x - (10.0 * tens(x)) - ones(x);
divided *= 10;
return (int)divided;
}