Page 1 of 1

Add IO to Vocore2 Ultimate

Posted: Tue Oct 27, 2020 4:45 pm
by ArkEngr
I really like the nice little plastic box that the Vocore2 Ultimate comes in. But I needed some additional connections to it so I added a connector as shown in the attachment.
The pins connect to the Vocore2 at 4 pins next to each other of GND, 3.3V, GPIO37, GPIO38 which gives you 2 IO pins and power and ground. With this setup I first used the ground and GPIO37 to power an OPTO 22 Model 120D10 solid state relay for controlling AC lamps around my house. The addition of a web page shows status and allows editing of cron jobs for timed or manual control.
Then I got to looking at the SHT20 in Vonger's blog. I wrote the program below to bit bang the i2c interface. Works nice to show temperature and humidity.

#include "stdio.h"
#include "unistd.h"
#include "sys/ioctl.h"
#include "sys/mman.h"
#include "fcntl.h"
#include "time.h"

#define NULPTR ((unsigned long *)0)

#define I2C_DATA_LINE 37
#define I2C_CLOCK_LINE 38
#define I2C_DATA_IN 0
#define I2C_DATA_OUT 1


/* Set Bits 32 - 63 */
#define GPIO_DSET1 0x0634

/* Clear Bits 32 - 63 */
#define GPIO_DCLR1 0x0644

/* Value in/out Bits 32 - 63 */
#define GPIO_DATA1 0x0624

/* Direction Bits 32 - 63 */
#define GPIO_CTRL_1 0x0604

/* Data mask Bit 37 */
#define GPIO_DATA 0x00000020

/* CLK mask Bit 38 */
#define GPIO_CLK 0x00000040

#define MAX_BUF 64
#define PAGE_SIZE 4096
#define MEM_BASE 0x10000000
#define SYSFS_GPIO_DIR "/sys/class/gpio"

unsigned long *mem = NULPTR;

/* vocore */
/****************************************************************
* mmap_page returns pointer to memory
****************************************************************/
unsigned long *mmap_page(void)
{
signed long fd = -1;
unsigned long *fmem = NULPTR;

fd = open("/dev/mem", O_RDWR);

if(fd < 0)
{
return NULL;
}

fmem = (unsigned long *)mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, MEM_BASE);

close(fd);

return fmem;
}

/* vocore */
/****************************************************************
* gpio_set_dir
****************************************************************/
void gpio_set_dir(unsigned int gpio, unsigned int out_flag)
{
if(out_flag)
{
*((unsigned long *)(mem + (GPIO_CTRL_1 >> 2))) = GPIO_CLK | GPIO_DATA;
}
else
{
*((unsigned long *)(mem + (GPIO_CTRL_1 >> 2))) = GPIO_CLK;
}
}

/* vocore */
/****************************************************************
* gpio clear bits
****************************************************************/
void gpioclearbits(unsigned char data_pin)
{
if(data_pin == I2C_DATA_LINE)
{
*((unsigned long *)(mem + (GPIO_DCLR1 >> 2))) = GPIO_DATA;
}
else
{
*((unsigned long *)(mem + (GPIO_DCLR1 >> 2))) = GPIO_CLK;
}
}

/* vocore */
/****************************************************************
* gpio set bits
****************************************************************/
void gpiosetbits(unsigned char data_pin)
{
if(data_pin == I2C_DATA_LINE)
{
*((unsigned long *)(mem + (GPIO_DSET1 >> 2))) = GPIO_DATA;
}
else
{
*((unsigned long *)(mem + (GPIO_DSET1 >> 2))) = GPIO_CLK;
}
}

/* vocore */
/****************************************************************
* gpio get bit
****************************************************************/
int i2c_getbit(void)
{
if((*((unsigned long *)(mem + (GPIO_DATA1 >> 2))) & GPIO_DATA) == GPIO_DATA)
{
return(1);
}
return(0);
}

/* vocore reg */
/****************************************************************
* gpio set dir out
****************************************************************/
void i2c_clk_out(void)
{
gpio_set_dir(I2C_CLOCK_LINE, I2C_DATA_OUT);
}

/* vocore reg */
/****************************************************************
* gpio set dir out
****************************************************************/
void i2c_dir_out(void)
{
gpio_set_dir(I2C_DATA_LINE, I2C_DATA_OUT);
}

/* vocore reg */
/****************************************************************
* gpio set dir in
****************************************************************/
void i2c_dir_in(void)
{
gpio_set_dir(I2C_DATA_LINE, I2C_DATA_IN);
}

/* vocore reg */
/****************************************************************
* i2c data set state
****************************************************************/
void i2c_data(int state)
{
if(state == 1)
{
gpiosetbits(I2C_DATA_LINE);
}
else
{
gpioclearbits(I2C_DATA_LINE);
}
}

/* vocore reg */
/****************************************************************
* i2c clk set state
****************************************************************/
void i2c_clk(int state)
{
if(state == 1)
{
gpiosetbits(I2C_CLOCK_LINE);
}
else
{
gpioclearbits(I2C_CLOCK_LINE);
}
}

// Read a byte from I2C bus and send the ack sequence
// Put islast = 1 is this is the last byte to receive from the slave

unsigned char i2c_inbyte(int islast)
{
unsigned char value = 0;
int bitvalue;
int i;

i2c_dir_in();

for(i = 0; i < 8; i++)
{
usleep(100); // sleep for 0.2 milliseconds
bitvalue = i2c_getbit();
value |= bitvalue;

i2c_clk(1);

if(i < 7)
{
value <<= 1;
}

usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);
usleep(100); // sleep for 0.2 milliseconds
}

i2c_dir_out();

if(islast == 0)
{
// Send Ack if is not the last byte to read
i2c_data(0);

usleep(100); // sleep for 0.2 milliseconds
i2c_clk(1);
usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);
usleep(200); // sleep for 0.2 milliseconds
i2c_dir_in();
}
else
{
// Send Nack if is the last byte to read
i2c_data(1);

usleep(100); // sleep for 0.2 milliseconds
i2c_clk(1);
usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);
usleep(200); // sleep for 0.2 milliseconds
}

return value;
}


// Initializate the I2C bus

void i2c_init(void)
{
mem = mmap_page();

if(mem == NULL)
{
printf("can not map memory.\n");
return;
}

i2c_dir_out();
i2c_clk(1);
i2c_data(1);
}

// Send a start sequence to I2C bus
// Data goes low before Clock

void i2c_start(void)
{
i2c_data(0);
usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);
usleep(200); // sleep for 0.2 milliseconds
}

// Send a stop sequence to I2C bus
// Data goes high after Clock

void i2c_stop(void)
{
i2c_clk(1);
usleep(200); // sleep for 0.2 milliseconds
i2c_data(1);
usleep(200); // sleep for 0.2 milliseconds
}

// Send a byte to the I2C bus and return the ack sequence from slave
// rtc
// 0 = Nack, 1=Ack

int i2c_outbyte(unsigned char x)
{
int i;
int ack;

for(i = 0; i < 8; i++)
{

if(x & 0x80)
{
i2c_data(1);
}
else
{
i2c_data(0);
}

usleep(100); // sleep for 0.2 milliseconds
i2c_clk(1);
usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);
usleep(100); // sleep for 0.2 milliseconds

x <<= 1;
}

i2c_dir_in();
usleep(100); // sleep for 0.2 milliseconds
i2c_clk(1);
ack = i2c_getbit();
usleep(200); // sleep for 0.2 milliseconds
i2c_clk(0);

usleep(100); // sleep for 0.2 milliseconds
i2c_dir_out();
i2c_data(0);
usleep(100); // sleep for 0.2 milliseconds

if(ack == 0)
{
return 1;
}
else
{
return 0;
}
}

int main(void)
{
int loop_count;
int i2c_slave;
int RH, Temp;
unsigned char RH_hi, RH_lo, T_hi, T_lo, crc;
float RH_float, Temp_float;

printf("Temperature/Humidity ver 3.3\n");

i2c_init();

// SHT20
// | 1 | 0 | 0 | 0 || 0 | 0 | 0 | R/W |
i2c_slave = 0x80;

i2c_start();

if(i2c_outbyte(i2c_slave | 0) == 0)
{
printf("NACK received %d\n", __LINE__);
i2c_stop();
return -1;
}

if(i2c_outbyte(0xF5) == 0) /* Read Humidity */
{
printf("NACK received %d\n", __LINE__);
i2c_stop();
return -1;
}

usleep(5); // sleep for 5 useconds
i2c_stop();

loop_count = 0;

do /* Wait for Ack during measurement */
{
i2c_start();

if(i2c_outbyte(i2c_slave | 1) == 0)
{
i2c_stop();
usleep(5); // sleep for 5 useconds
printf("Meas NACK received %d\n", __LINE__);
}
else
{
break;
}

loop_count++;

} while(loop_count < 10000000);


RH_hi = i2c_inbyte(0);
RH_lo = i2c_inbyte(0);

crc = i2c_inbyte(1);

RH = (((unsigned int)(RH_hi)) << 8) + RH_lo;
RH = RH & 0xFFFC;
RH_float = RH;
RH_float = RH_float / 65536U;
RH_float = RH_float * 125.0f;
RH_float = RH_float - 6.0f;

i2c_stop();

// Show the humidity level
printf("Humidity = %6.2f %% (0x%02X 0x%02X)\n", RH_float, RH_hi, RH_lo);

i2c_start();

if(i2c_outbyte(i2c_slave | 0) == 0)
{
printf("NACK received %d\n", __LINE__);
i2c_stop();
return -1;
}

if(i2c_outbyte(0xF3) == 0) /* Read Temperature */
{
printf("NACK received %d\n", __LINE__);
i2c_stop();
return -1;
}

usleep(5); // sleep for 5 useconds
i2c_stop();

loop_count = 0;

do /* Wait for Ack during measurement */
{
i2c_start();

if(i2c_outbyte(i2c_slave | 1) == 0)
{
i2c_stop();
usleep(5); // sleep for 5 useconds
printf("Meas NACK received %d\n", __LINE__);
}
else
{
break;
}

loop_count++;

}while(loop_count < 10000000);


T_hi = i2c_inbyte(0);
T_lo = i2c_inbyte(0);

crc = i2c_inbyte(1);

Temp = (((unsigned int)(T_hi)) << 8) + T_lo;
Temp = Temp & 0xFFFC;
Temp_float = Temp;
Temp_float = Temp_float / 65536U;
Temp_float = Temp_float * 175.72f;
Temp_float = Temp_float - 46.85f;
Temp_float = (((Temp_float + 40.0f) * 9U) / 5U) - 40U;

i2c_stop();

// Show the humidity level
printf("Temperature = %6.2f deg. F (0x%02X 0x%02X)\n\n", Temp_float, T_hi, T_lo);

return 0;
}

Re: Add IO to Vocore2 Ultimate

Posted: Fri Nov 13, 2020 3:10 am
by ArkEngr
This is the web interface I made to run a light attached to the Vocore2 Ultimate via the SSR I mentioned.

Re: Add IO to Vocore2 Ultimate

Posted: Fri Nov 13, 2020 3:12 am
by ArkEngr
Hardware pictures