Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposed I2C driver and MOS API implementation #115

Merged
merged 1 commit into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MOS.wsp
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ ptn_Child1=Frames
[WorkState_v1_2.Frames]
ptn_Child1=ChildFrames

[WorkState_v1_2.Frames.ChildFrames]

3 changes: 2 additions & 1 deletion MOS.zdsproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<file filter-key="">src\config.h</file>
<file filter-key="">src\mos_api.inc</file>
<file filter-key="">src\defines.h</file>
<file filter-key="">src\i2c.c</file>
</files>

<!-- configuration information -->
Expand Down Expand Up @@ -284,4 +285,4 @@
<breakpoints>
</breakpoints>

</project>
</project>
3 changes: 3 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "ff.h"
#include "clock.h"
#include "mos.h"
#include "i2c.h"

#define MOS_version 1
#define MOS_revision 4
Expand All @@ -51,6 +52,7 @@ extern void * set_vector(unsigned int vector, void(*handler)(void));

extern void vblank_handler(void);
extern void uart0_handler(void);
extern void i2c_handler(void);

extern char coldBoot; // 1 = cold boot, 0 = warm boot
extern volatile char keycode; // Keycode
Expand Down Expand Up @@ -98,6 +100,7 @@ int wait_ESP32(UART * pUART, UINT24 baudRate) {
void init_interrupts(void) {
set_vector(PORTB1_IVECT, vblank_handler); // 0x32
set_vector(UART0_IVECT, uart0_handler); // 0x18
set_vector(I2C_IVECT, i2c_handler); // 0x1C
}

// The main loop
Expand Down
155 changes: 155 additions & 0 deletions src/i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Title: AGON MOS - I2C code
* Author: Jeroen Venema
* Created: 07/11/2023
* Last Updated: 10/11/2023
*
* Modinfo:
*/

#include <ez80.h>
#include "i2c.h"
#include <defines.h>
#include "timer.h"

// Set I2C clock and sampling frequency
void I2C_setfrequency(UINT8 id) {
switch(id) {
case(I2C_SPEED_115200):
I2C_CCR = (0x01<<3) | 0x03; // 115.2KHz fast-mode (400KHz max), sampling at 4.6MHz
break;
case(I2C_SPEED_230400):
I2C_CCR = (0x01<<3) | 0x02; // 230.4KHz fast-mode (400KHz max), sampling at 2.3Mhz
break;
case(I2C_SPEED_57600):
default:
I2C_CCR = (0x01<<3) | 0x04; // 57.6KHz default standard-mode (100KHz max), sampling at 1.15Mhz
}
}

// Initializes the I2C bus
void init_I2C(void) {
i2c_msg_size = 0;
CLK_PPD1 = CLK_PPD_I2C_OFF; // Power Down I2C block before enabling it, avoid locking bug
I2C_CTL = I2C_CTL_ENAB; // Enable I2C block, don't enable interrupts yet
I2C_setfrequency(0);
CLK_PPD1 = 0x0; // Power up I2C block
}

// Internal function
void I2C_handletimeout(void) {
// reset the interface
I2C_CTL = 0;
init_I2C();
}

// Open the I2C bus, register the driver interrupt
// Parameters: None
// Returns: None
void mos_I2C_OPEN(UINT8 frequency) {
init_I2C();
I2C_setfrequency(frequency);
}

// Close the I2C bus, deregister the driver interrupt
// Parameters: None
// Returns: None
void mos_I2C_CLOSE(void) {
CLK_PPD1 = CLK_PPD_I2C_OFF; // Power Down I2C block
I2C_CTL &= ~(I2C_CTL_ENAB); // Disable I2C block
}

// Write a number of bytes to an address on the I2C bus
// Parameters:
// - i2c_address: I2C address of the slave device
// - size: number of bytes to write
// - buffer: pointer to the first byte to write
// Returns:
// - 0 on success, or errorcode
UINT8 mos_I2C_WRITE(UINT8 i2c_address, UINT8 size, char * buffer) {

// send maximum of 32 bytes in a single I2C transaction
if(size > I2C_MAX_BUFFERLENGTH) size = I2C_MAX_BUFFERLENGTH;
if(i2c_address > 127) return RET_NORESPONSE;
// wait for IDLE status
init_timer0(1, 16, 0x00); // 1ms timer for delay
enable_timer0(1);
while(i2c_role) {
// anything but IDLE (00)
if(get_timer0() > I2C_TIMEOUTMS) {
I2C_handletimeout();
enable_timer0(0); // Disable timer
return RET_ARB_LOST;
}
}
enable_timer0(0);

i2c_msg_ptr = buffer;
i2c_msg_size = size;
i2c_role = I2C_MTX; // MTX - Master Transmit Mode
i2c_error = RET_OK;
i2c_slave_rw = i2c_address << 1; // shift one bit left, 0 on bit 0 == write action on I2C

I2C_CTL = I2C_CTL_IEN | I2C_CTL_ENAB | I2C_CTL_STA; // send start condition

init_timer0(1, 16, 0x00); // 1ms timer for delay
enable_timer0(1);
while(i2c_role == I2C_MTX) { // while MTX
if(get_timer0() > I2C_TIMEOUTMS) {
I2C_handletimeout();
enable_timer0(0); // Disable timer
return RET_DATA_NACK;
}
}

enable_timer0(0); // Disable timer
return i2c_error;
}

// Read a number of bytes from an i2c_address on the I2C bus
// Parameters:
// - i2c_address: I2C address of the slave device
// - size: number of bytes to read
// - buffer: pointer to the first byte to read
// Returns:
// - 0 on success, or errorcode
UINT8 mos_I2C_READ(UINT8 i2c_address, UINT8 size, char* buffer)
{
if(size == 0) return 0;
if(i2c_address > 127) return RET_NORESPONSE;
// receive maximum of 32 bytes in a single I2C transaction
if(size > I2C_MAX_BUFFERLENGTH) size = I2C_MAX_BUFFERLENGTH;

// wait for IDLE status
init_timer0(1, 16, 0x00); // 1ms timer for delay
enable_timer0(1);
while(i2c_role) {
// anything but IDLE (00)
if(get_timer0() > I2C_TIMEOUTMS) {
I2C_handletimeout();
enable_timer0(0); // Disable timer
return RET_ARB_LOST;
}
}
enable_timer0(0);
i2c_msg_ptr = buffer;
i2c_msg_size = size;
i2c_role = I2C_MRX; // MRX mode
i2c_error = RET_OK;
i2c_slave_rw = (1<<0); // receive bit 0
i2c_slave_rw |= i2c_address << 1; // shift 7-bit address one bit left

I2C_CTL = I2C_CTL_IEN | I2C_CTL_ENAB | I2C_CTL_STA; // send start condition

init_timer0(1, 16, 0x00); // 1ms timer for delay
enable_timer0(1);
while(i2c_role == I2C_MRX) {
if(get_timer0() > I2C_TIMEOUTMS) {
I2C_handletimeout();
enable_timer0(0); // Disable timer
return RET_ARB_LOST;
}
}
enable_timer0(0); // Disable timer
return i2c_error;
}
51 changes: 51 additions & 0 deletions src/i2c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef _I2C_H_
#define _I2C_H_

#include <defines.h>


extern volatile char i2c_slave_rw;
extern volatile char i2c_error;
extern volatile char i2c_role;
extern volatile UINT8 i2c_msg_size;
extern volatile char * i2c_msg_ptr;

// I2C_CTL register bits
#define I2C_CTL_IEN (1<<7)
#define I2C_CTL_ENAB (1<<6)
#define I2C_CTL_STA (1<<5)
#define I2C_CTL_STP (1<<4)
#define I2C_CTL_IFLG (1<<3)
#define I2C_CTL_AAK (1<<2)

// ez80 PPD register bits
#define CLK_PPD_I2C_OFF (1<<2)

// I2C return codes to caller
#define RET_OK 0x00
#define RET_NORESPONSE 0x01
#define RET_DATA_NACK 0x02
#define RET_ARB_LOST 0x04
#define RET_BUS_ERROR 0x08

// I2C constants
#define I2C_MAX_BUFFERLENGTH 32
#define I2C_TIMEOUTMS 2000
#define I2C_SPEED_57600 0x01
#define I2C_SPEED_115200 0x02
#define I2C_SPEED_230400 0x03

// I2C role state
#define I2C_IDLE 0x00
#define I2C_MTX 0x01
#define I2C_MRX 0x02
#define I2C_SRX 0x04
#define I2C_STX 0x08

void init_I2C(void);
void mos_I2C_OPEN(UINT8 frequency);
void mos_I2C_CLOSE(void);
UINT8 mos_I2C_WRITE(UINT8 i2c_address, UINT8 size, char * buffer);
UINT8 mos_I2C_READ(UINT8 i2c_address, UINT8 size, char * buffer);

#endif _I2C_H_
21 changes: 21 additions & 0 deletions src/i2c.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
;* Return status codes to read/write caller
RET_OK .equ 00h ; ok - caller sets this at entry
RET_NORESPONSE .equ 01h ; address sent, nack received
RET_DATA_NACK .equ 02h ; data sent, nack received
RET_ARB_LOST .equ 04h ; arbitration lost
RET_BUS_ERROR .equ 08h ; Bus error

;* I2C ROLE STATUS
I2C_IDLE .equ 00h
I2C_MTX .equ 01h
I2C_MRX .equ 02h
I2C_SRX .equ 04h
I2C_STX .equ 08h

;* I2C_CTL bits
I2C_CTL_IEN .equ 10000000b
I2C_CTL_ENAB .equ 01000000b
I2C_CTL_STA .equ 00100000b
I2C_CTL_STP .equ 00010000b
I2C_CTL_IFLG .equ 00001000b
I2C_CTL_AAK .equ 00000100b
Loading