Page 2 of 2

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 1:48 pm
by martyn_hill
Hi Peter

Peter wrote:My hope was that bitbanging I2C is simple enough, so people could live without me providing example code. It seems not so - and I stille have providing I2C example code on my to-do-list.


Perhaps we can help here, with just a teensy-bit of guidance from your (busy) self!

a) Could the Minerva MkII I2C primitives be used as a framework within Q68, once the port addresses are replaced? If so, M_ii_drive_asm should be a sufficient starting point for those of us with more cycles to spare than you :-)

b) Can you confirm that the 'keys_q68' include definitions file currently available in the SMSQ source is incorrect, as it has the following:

[src_keys_q68, lines 115..116]
i2c_scl equ $1c00c ; ?
i2c_sda equ $1c00e ; ?

Regards - and thank you again for Q68!

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 3:29 pm
by Pr0f
Not 68K, but probably not too difficult to transpose to 68K c or assembler:

https://calcium3000.wordpress.com/2016/ ... al-part-i/

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 7:01 pm
by Whopper
Peter wrote:The Q68 manual is correct regarding i2C addresses. Note that the clock register is output only, nothing you can read there.


Peter,

Thank you for this. Now I need to check the actual pins and their levels, but I would have needed to do that anyway.

If the CLK ($1C1C0) is un readable, how do you check for contention? Or do you just 'go for it'?

You are, of course, right BitBanging I2C is fairly simple and should present no problems to anyone serious enough to have a go at it.


Thanks,


Whopper

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 8:36 pm
by Derek_Stewart
martyn_hill wrote:b) Can you confirm that the 'keys_q68' include definitions file currently available in the SMSQ source is incorrect, as it has the following:

[src_keys_q68, lines 115..116]
i2c_scl equ $1c00c ; ?
i2c_sda equ $1c00e ; ?

Hi Martin,

I had a look at the SMSQ/E Q68 key file, the drginition of; i2c_scl and i2c_sda is incorrect.

I will ask Wolfgang to change the equates.

But on saying this the I2C or IIC is not programmed within SMSQ/E, which why we have to absolute addresses rather than Traps or Vectors.

The Minerva MKIi drive_asm file defines access to the I2C interface, which is a little more complicated than the Q68.

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 9:36 pm
by Peter
martyn_hill wrote:Can you confirm that the 'keys_q68' include definitions file currently available in the SMSQ source is incorrect, as it has the following:

[src_keys_q68, lines 115..116]
i2c_scl equ $1c00c ; ?
i2c_sda equ $1c00e ; ?

Yes incorrect. It has historical reasons. The hardware was changed toward longword alignment after the initial SMSQ/E port was already done.
Thank YOU for the QL network driver!

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 9:43 pm
by Peter
To get you going, here's a quick hack for the TF Services Analogue interface.
The wait(500000) in main() should of course be replaced by a non-polling delay.

Code: Select all

#include <stdio.h>

#define TIME_CPU (* (volatile unsigned long*) 0x1C060)

#define I2C_SCL (* (volatile unsigned char*) 0x1C1C0)
#define I2C_SDA (* (volatile unsigned char*) 0x1C1C4)

void wait(unsigned int usec)
{
  unsigned long start, diff;
 
  start = TIME_CPU;
  diff = 40*usec;
  while ((TIME_CPU-start) < diff);
}

void i2c_dly(void)
{
  wait(100); /* Not at maximum speed */
}

void i2c_start(void)
{
  I2C_SDA = 1; i2c_dly();
  I2C_SCL = 1; i2c_dly();
  I2C_SDA = 0; i2c_dly();
  I2C_SCL = 0; i2c_dly();
}

void i2c_stop(void)
{
  I2C_SDA = 0; i2c_dly();
  I2C_SCL = 1; i2c_dly();
  I2C_SDA = 1; i2c_dly();
}

unsigned char i2c_rx(char ack)
{
  unsigned char x, d=0;
  I2C_SDA = 1; i2c_dly();
  for(x=0; x<8; x++)
  {
    d <<= 1;
    I2C_SCL = 1; i2c_dly();
    if(I2C_SDA)
      d |= 1;
    I2C_SCL = 0; i2c_dly();
  }
  if(ack)
    I2C_SDA = 0;
  else
    I2C_SDA = 1;
  i2c_dly();
  I2C_SCL = 1; i2c_dly();
  I2C_SCL = 0; i2c_dly();
  I2C_SDA = 1; i2c_dly();
  return d;
}

unsigned char i2c_tx(unsigned char d)
{
  char x;
  unsigned char ack;
  for(x=8; x; x--)
  {
    if(d & 0x80)
      I2C_SDA = 1;
    else
      I2C_SDA = 0;
    i2c_dly();
    d <<= 1;
    I2C_SCL = 1; i2c_dly();
    I2C_SCL = 0; i2c_dly();
  }
  I2C_SDA = 1; i2c_dly();
  I2C_SCL = 1; i2c_dly();
  ack = !I2C_SDA;
  I2C_SCL = 0; i2c_dly();
  return ack;
}

void PCF8591InitADC(unsigned char adr)
{
  unsigned char ack;
  i2c_start();
  /* 1 0 0 1 A2 A1 A0 R/W */
  ack = i2c_tx(0x90 | (adr<<1));
  if (!ack)
    printf("Missing Acknowledge after write address byte\n");
  /* Analogue output enabled, 4 single-ended inputs, auto-increment */
  /* Start with channel 1, so we are at channel 0 when reading */
  ack = i2c_tx(0x45|adr);
  if (!ack)
    printf("Missing Acknowledge after control byte\n");
  i2c_stop();
}

void PCF8591ReadADC(unsigned char adr, unsigned char data[])
{
  unsigned char ack;
  i2c_start();
  /* 1 0 0 1 A2 A1 A0 R/W */
  ack = i2c_tx(0x91 | (adr<<1));
  if (!ack)
    printf("Missing Acknowledge after read address byte\n");
  data[0] = i2c_rx(1);
  data[1] = i2c_rx(1);
  data[2] = i2c_rx(1);
  data[3] = i2c_rx(0);
  i2c_stop();
}

void main(void)
{
  static unsigned char data[4];
 
  PCF8591InitADC(0);
  do
  {
    PCF8591ReadADC(0, data);
    printf("PCF8591 analogue inputs: $%02X $%02X $%02X $%02X\n",
      (int)data[0], (int)data[1], (int)data[2], (int)data[3]);
    wait(500000);
  }
  while(1);
}

Re: Q68 I2C addresses.

Posted: Mon Jun 10, 2019 11:02 pm
by Derek_Stewart
Hi,

In addition to Peter's Q68 I2C example code.

Here are some I2C Resources:

I2C Primer
https://www.i2c-bus.org/i2c-primer/

Sparkfun I2C Tutorial
https://learn.sparkfun.com/tutorials/i2c/

Wikipedia I2C Article
http://en.wikipedia.org/wiki/I%C2%B2C

I2C-bus specification and user manual
UM10204.pdf
I2C-bus specification and user manual
(1.33 MiB) Downloaded 8 times