Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Anders Blomdell
processer
Commits
06c4b54e
Commit
06c4b54e
authored
Oct 07, 2019
by
Anders Blomdell
Browse files
Simple text based test of China I/O basic functionality
parent
0334488f
Changes
3
Hide whitespace changes
Inline
Side-by-side
china_io-2019/avr/Makefile
0 → 100644
View file @
06c4b54e
TARGETS
=
china-io china-io-test
china-io.ARCH
=
avr
china-io.CHIP
=
atmega32
# 14.7456 MHz crystal, brown out
china-io.FUSE
=
--wr_fuse_l
=
0x1f
--wr_fuse_h
=
0xd9
--wr_fuse_e
=
0xff
china-io.FUSE_L
=
0x1f
china-io.FUSE_H
=
0xd9
china-io.C
=
china-io
china-io.H
=
../lib/serialio i2c_master
china-io-test.ARCH
=
avr
china-io-test.CHIP
=
atmega32
# 14.7456 MHz crystal, brown out
china-io-test.FUSE
=
--wr_fuse_l
=
0x1f
--wr_fuse_h
=
0xd9
--wr_fuse_e
=
0xff
china-io-test.FUSE_L
=
0x1f
china-io-test.FUSE_H
=
0xd9
china-io-test.C
=
china-io-test
china-io-test.H
=
i2c_master
include
../../lib/avr/Makefile.common
china_io-2019/avr/china-io-test.c
0 → 100644
View file @
06c4b54e
#include
<avr/interrupt.h>
#include
<avr/io.h>
#include
<inttypes.h>
#include
<stdio.h>
#include
<util/twi.h>
#include
"i2c_master.h"
#define DDR_SPI DDRB
#define DD_MISO PB6
#define DD_MOSI PB5
#define DD_SCK PB7
#define DD_SS PB4
#define PORT_SPI PORTB
static
void
putch
(
unsigned
char
ch
)
{
while
((
UCSRA
&
0x20
)
==
0
)
{};
UDR
=
ch
;
}
static
void
putonehex
(
char
i
)
{
if
(
i
<
10
)
{
putch
(
i
+
'0'
);
}
else
if
(
i
<
16
)
{
putch
(
i
-
10
+
'a'
);
}
}
static
void
puthex
(
char
value
)
{
putonehex
((
value
>>
4
)
&
0x0f
);
putonehex
(
value
&
0x0f
);
}
void
putstr
(
char
*
message
)
{
for
(
int
i
=
0
;
message
[
i
]
;
i
++
)
{
putch
(
message
[
i
]);
}
}
void
putint32
(
int32_t
value
)
{
char
buf
[
20
];
snprintf
(
buf
,
sizeof
(
buf
),
"%8ld"
,
value
);
putstr
(
buf
);
}
void
putint16
(
int16_t
value
)
{
char
buf
[
20
];
snprintf
(
buf
,
sizeof
(
buf
),
"%8d"
,
value
);
putstr
(
buf
);
}
static
uint8_t
ADS8694_W
(
uint8_t
length
,
const
__flash
uint8_t
*
data
)
{
DDR_SPI
|=
(
1
<<
DD_MOSI
)
|
(
1
<<
DD_SCK
)
|
(
1
<<
DD_SS
);
SPCR
&=
(
1
<<
SPIE
);
SPCR
=
(
1
<<
SPE
)
|
(
1
<<
MSTR
)
|
(
1
<<
CPHA
);
SPSR
=
(
1
<<
SPI2X
);
PORT_SPI
|=
(
1
<<
DD_MISO
);
// Pull up
PORT_SPI
&=
~
(
1
<<
DD_SS
);
for
(
uint8_t
i
=
0
;
i
<
length
;
i
++
)
{
SPDR
=
data
[
i
];
while
((
SPSR
&
(
1
<<
SPIF
))
==
0
)
{}
}
uint8_t
dummy
=
SPDR
;
// Clear SPIF flag
PORT_SPI
|=
(
1
<<
DD_SS
);
return
dummy
;
}
/*
* DAC8574 4-channel D/A convert
*/
#define DAC8574ADDR 0x4c
static
volatile
struct
dac8574
{
union
dac8574_channel
{
uint8_t
bytes
[
3
];
struct
{
uint8_t
control
;
uint8_t
data
[
2
];
}
reg
;
}
a
,
b
,
c
,
d
;
}
dac8574
=
{
.
a
=
{
.
reg
=
{
.
control
=
0x10
}
},
.
b
=
{
.
reg
=
{
.
control
=
0x12
}
},
.
c
=
{
.
reg
=
{
.
control
=
0x14
}
},
.
d
=
{
.
reg
=
{
.
control
=
0x16
}
},
};
static
void
dac8574_set_chan
(
volatile
union
dac8574_channel
*
channel
,
int
value
)
{
channel
->
reg
.
data
[
0
]
=
(
value
&
0xff00
)
>>
8
;
channel
->
reg
.
data
[
1
]
=
(
value
&
0x00ff
);
}
static
const
__flash
struct
i2c_transcation
write_all
[]
=
{
I2C_WRITE_RAM
(
DAC8574ADDR
,
3
,
dac8574
.
a
.
bytes
),
I2C_WRITE_RAM
(
DAC8574ADDR
,
3
,
dac8574
.
b
.
bytes
),
I2C_WRITE_RAM
(
DAC8574ADDR
,
3
,
dac8574
.
c
.
bytes
),
I2C_WRITE_RAM
(
DAC8574ADDR
,
3
,
dac8574
.
d
.
bytes
),
I2C_END
()
};
static
volatile
int32_t
ADS8694_value
[
4
]
=
{
0
,
0
,
0
,
0
};
SIGNAL
(
TIMER1_COMPA_vect
)
{
unsigned
char
data
[
5
];
SPCR
=
(
1
<<
SPE
)
|
(
1
<<
MSTR
)
|
(
1
<<
CPHA
);
PORT_SPI
&=
~
(
1
<<
DD_SS
);
// Chip select
SPDR
=
0x00
;
// NOP
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
while
((
SPSR
&
0x80
)
==
0
)
{
}
data
[
i
]
=
SPDR
;
if
(
i
<
4
)
{
// More to read
SPDR
=
0
;
}
}
PORT_SPI
|=
(
1
<<
DD_SS
);
// Chip deselect
union
{
int32_t
i
;
unsigned
char
b
[
4
];
}
v
;
uint8_t
chan
;
v
.
i
=
0
;
v
.
b
[
2
]
=
data
[
2
];
v
.
b
[
1
]
=
data
[
3
];
v
.
b
[
0
]
=
data
[
4
];
chan
=
(
v
.
i
>>
2
)
&
0xf
;
ADS8694_value
[
chan
]
=
(
v
.
i
>>
6
)
-
0x20000
;
}
static
int16_t
v
=
0
;
SIGNAL
(
USART_RXC_vect
)
{
char
ch
=
UDR
;
puthex
(
ch
);
putstr
(
"RX Status:"
);
puthex
(
TWSR
);
puthex
(
TWCR
);
if
(
ch
==
'+'
)
{
v
+=
1024
;
}
else
if
(
ch
==
'-'
)
{
v
-=
1024
;
}
putstr
(
"
\r\n
"
);
}
int
main
()
{
/* Setup serial port */
UCSRA
=
0x00
;
// USART:
UCSRB
=
0x98
;
// USART: RxIntEnable|RxEnable|TxEnable
UCSRC
=
0x86
;
// USART: 8bit, no parity
UBRRH
=
0
;
// USART: 115200 @ 14.7456MHz
UBRRL
=
7
;
// USART: 115200 @ 14.7456MHz
/* Setup timer1 */
TCCR1A
=
0x00
;
// Normal port mode (no output)
TCCR1B
=
0x09
;
// Clock / 1
OCR1A
=
0x3fff
;
TIMSK
=
0x10
;
// Enable Timer1 compare A interrupts
/* Setup I2C (TWI), used by DAC8574 */
TWBR
=
0x10
;
TWSR
=
0x00
;
/* Setup DAC8574 (SPI setup is done in ADS8694_W) */
static
const
__flash
uint8_t
RST
[]
=
{
0x85
,
0x00
,
0x00
};
static
const
__flash
uint8_t
SEQUENCE
[]
=
{
(
0x01
<<
1
)
|
0x01
,
0x0f
,
0x00
};
static
const
__flash
uint8_t
FEATURES
[]
=
{
(
0x03
<<
1
)
|
0x01
,
0x03
,
0x00
};
static
const
__flash
uint8_t
AUTO_RST
[]
=
{
0xa0
,
0x00
,
0x00
,
0x00
,
0x00
};
ADS8694_W
(
3
,
RST
);
ADS8694_W
(
3
,
SEQUENCE
);
ADS8694_W
(
3
,
FEATURES
);
ADS8694_W
(
5
,
AUTO_RST
);
sei
();
// Global interrupt enable
putstr
(
"
\r\n\r\n
"
);
i2c_start
(
write_all
);
while
(
1
)
{
struct
dac8574
tmp
;
dac8574_set_chan
(
&
tmp
.
a
,
0x8000
);
dac8574_set_chan
(
&
tmp
.
b
,
0x8000
);
dac8574_set_chan
(
&
tmp
.
c
,
v
+
0x0000
);
dac8574_set_chan
(
&
tmp
.
d
,
v
+
0x8000
);
// v = (v + 1024) & 0xffff;
putstr
(
"i2c status="
);
putint16
(
i2c_ctx
.
status
);
putstr
(
" v="
);
putint16
(
v
);
putint16
(
v
+
0x8000
);
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
putint32
(
ADS8694_value
[
i
]);
}
putstr
(
"
\r
"
);
if
(
i2c_idle
())
{
cli
();
*
dac8574
.
a
.
reg
.
data
=
*
tmp
.
a
.
reg
.
data
;
*
dac8574
.
b
.
reg
.
data
=
*
tmp
.
b
.
reg
.
data
;
*
dac8574
.
c
.
reg
.
data
=
*
tmp
.
c
.
reg
.
data
;
*
dac8574
.
d
.
reg
.
data
=
*
tmp
.
d
.
reg
.
data
;
i2c_start
(
write_all
);
sei
();
putstr
(
"
\r\n
"
);
}
}
}
china_io-2019/avr/i2c_master.h
0 → 100644
View file @
06c4b54e
#ifndef __I2C_MASTER_H__
#define __I2C_MASTER_H__
#include
<util/atomic.h>
enum
i2c_op
{
I2C_R_OP
=
0x01
,
I2C_W_FLASH_OP
,
I2C_W_RAM_OP
,
I2C_W_1_OP
,
I2C_W_2_OP
,
I2C_W_3_OP
,
I2C_CALL_OP
,
I2C_CHAIN_OP
,
I2C_END_OP
,
};
struct
i2c_transcation
{
enum
i2c_op
op
:
8
;
union
{
struct
i2c_read
{
unsigned
char
address
;
unsigned
char
count
;
void
volatile
*
data
;
}
read
;
struct
i2c_write_flash
{
unsigned
char
address
;
unsigned
char
count
;
const
volatile
unsigned
__flash
char
*
data
;
}
write_flash
;
struct
i2c_write_ram
{
unsigned
char
address
;
unsigned
char
count
;
const
volatile
unsigned
char
*
data
;
}
write_ram
;
struct
i2c_write
{
unsigned
char
address
;
const
volatile
unsigned
char
data
[
3
];
}
write
;
struct
i2c_callback
{
unsigned
char
(
*
function
)(
const
volatile
void
*
context
);
const
volatile
void
*
context
;
}
callback
;
struct
i2c_chain
{
const
__flash
struct
i2c_transcation
*
transaction
;
}
chain
;
};
};
static
volatile
struct
i2c_ctx
{
const
__flash
struct
i2c_transcation
*
transaction
;
// unsigned char length;
unsigned
char
pos
;
char
status
;
}
i2c_ctx
;
#define I2C_READ(ADDR, COUNT, DATA) \
{.op=I2C_R_OP,{.read={.address=ADDR,.count=COUNT, .data=DATA}}}
#define I2C_WRITE_FLASH(ADDR, COUNT, DATA) \
{.op=I2C_W_FLASH_OP,{.write_flash={.address=ADDR,.count=COUNT,.data=DATA}}}
#define I2C_WRITE_RAM(ADDR, COUNT, DATA) \
{.op=I2C_W_RAM_OP,{.write_ram={.address=ADDR,.count=COUNT,.data=DATA}}}
#define I2C_WRITE_1(ADDR, DATA0) \
{.op=I2C_W_1_OP,{.write={.address=ADDR, \
.data[0]=DATA0}}}
#define I2C_WRITE_2(ADDR, DATA0, DATA1) \
{.op=I2C_W_2_OP,{.write={.address=ADDR, \
.data[0]=DATA0, \
.data[1]=DATA1}}}
#define I2C_WRITE_3(ADDR, DATA0, DATA1, DATA2) \
{.op=I2C_W_3_OP,{.write={.address=ADDR, \
.data[0]=DATA0, \
.data[1]=DATA1, \
.data[2]=DATA2}}}
#define I2C_CALLBACK(FUNC, CONTEXT) \
{.op=I2C_CALL_OP,{.callback={.function=FUNC,.context=CONTEXT}}}
#define I2C_CHAIN(TRANSACTION) \
{.op=I2C_CHAIN_OP,{.chain={.transaction=TRANSACTION}}}
#define I2C_END() \
{.op=I2C_END_OP,{}}
static
unsigned
char
i2c_chain
(
const
__flash
struct
i2c_transcation
*
transaction
)
{
i2c_ctx
.
transaction
=
transaction
;
i2c_ctx
.
pos
=
0
;
i2c_ctx
.
status
=
0
;
return
0
;
}
static
unsigned
char
i2c_start
(
const
__flash
struct
i2c_transcation
*
transaction
)
{
i2c_chain
(
transaction
);
TWCR
=
(
1
<<
TWINT
)
|
(
1
<<
TWSTA
)
|
(
1
<<
TWEN
)
|
(
1
<<
TWIE
);
return
0
;
}
/* Return number of bytes in current transaction */
static
unsigned
char
i2c_count
()
{
struct
i2c_transcation
tr
=
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
];
switch
(
tr
.
op
)
{
case
I2C_CALL_OP
:
return
0
;
// ERROR
case
I2C_R_OP
:
return
tr
.
read
.
count
;
case
I2C_W_FLASH_OP
:
return
tr
.
write_flash
.
count
;
case
I2C_W_RAM_OP
:
return
tr
.
write_ram
.
count
;
case
I2C_W_1_OP
:
return
1
;
case
I2C_W_2_OP
:
return
2
;
case
I2C_W_3_OP
:
return
3
;
case
I2C_CHAIN_OP
:
return
0
;
// ERROR
case
I2C_END_OP
:
return
0
;
// ERROR
}
return
0
;
}
static
unsigned
char
i2c_get_data
(
unsigned
char
index
)
{
struct
i2c_transcation
tr
=
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
];
switch
(
tr
.
op
)
{
case
I2C_CALL_OP
:
return
0
;
// ERROR
case
I2C_R_OP
:
return
0
;
// ERROR
case
I2C_W_FLASH_OP
:
return
tr
.
write_flash
.
data
[
index
];
case
I2C_W_RAM_OP
:
return
tr
.
write_ram
.
data
[
index
];
case
I2C_W_1_OP
:
return
tr
.
write
.
data
[
index
];
case
I2C_W_2_OP
:
return
tr
.
write
.
data
[
index
];
case
I2C_W_3_OP
:
return
tr
.
write
.
data
[
index
];
case
I2C_CHAIN_OP
:
return
0
;
// ERROR
case
I2C_END_OP
:
return
0
;
// ERROR
}
return
0
;
}
static
void
i2c_put_data
(
unsigned
char
index
,
unsigned
char
data
)
{
struct
i2c_transcation
tr
=
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
];
switch
(
tr
.
op
)
{
case
I2C_CALL_OP
:
break
;
case
I2C_R_OP
:
{
if
(
index
<
tr
.
read
.
count
)
{
((
unsigned
char
*
)
tr
.
read
.
data
)[
index
]
=
data
;
}
}
break
;
case
I2C_W_FLASH_OP
:
break
;
case
I2C_W_RAM_OP
:
break
;
case
I2C_W_1_OP
:
break
;
case
I2C_W_2_OP
:
break
;
case
I2C_W_3_OP
:
break
;
case
I2C_CHAIN_OP
:
break
;
case
I2C_END_OP
:
break
;
}
}
static
char
i2c_callback
()
{
while
(
i2c_ctx
.
status
==
0
)
{
enum
i2c_op
op
=
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
;
if
(
op
==
I2C_END_OP
)
{
break
;
}
else
if
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
==
I2C_CALL_OP
)
{
struct
i2c_callback
cb
=
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
callback
;
i2c_ctx
.
status
=
cb
.
function
(
cb
.
context
);
if
(
i2c_ctx
.
status
==
0
)
{
i2c_ctx
.
pos
++
;
continue
;
}
}
else
if
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
==
I2C_CHAIN_OP
)
{
i2c_chain
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
chain
.
transaction
);
continue
;
}
else
{
break
;
}
}
return
i2c_ctx
.
status
;
}
static
char
i2c_next
()
{
#if 0
putstr("POS: ");
puthex(i2c_ctx.pos);
putstr(" OP: ");
puthex( i2c_ctx.transaction[i2c_ctx.pos].op);
putstr("\r\n");
#endif
if
(
i2c_ctx
.
status
!=
0
)
{
return
i2c_ctx
.
status
;
}
if
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
!=
I2C_END_OP
)
{
i2c_ctx
.
pos
++
;
i2c_callback
();
}
if
(
i2c_ctx
.
status
!=
0
)
{
return
i2c_ctx
.
status
;
}
return
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
!=
I2C_END_OP
;
}
static
char
i2c_more
(
unsigned
char
index
)
{
if
(
i2c_ctx
.
status
!=
0
)
{
return
i2c_ctx
.
status
;
}
return
index
<
i2c_count
();
}
static
char
i2c_idle
()
{
char
result
=
1
;
ATOMIC_BLOCK
(
ATOMIC_RESTORESTATE
)
{
if
(
i2c_ctx
.
transaction
&&
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
!=
I2C_END_OP
)
{
result
=
0
;
}
}
return
result
;
}
SIGNAL
(
TWI_vect
)
{
// unsigned char twsr = TWSR;
unsigned
char
twcr
=
0x00
;
static
unsigned
char
data_pos
=
0x00
;
// Consume callback operations
if
(
i2c_callback
()
!=
0
)
{
// putstr("Error\r\n");
}
switch
(
TW_STATUS
)
{
case
TW_START
:
case
TW_REP_START
:
{
switch
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
op
)
{
case
I2C_CALL_OP
:
case
I2C_CHAIN_OP
:
case
I2C_END_OP
:
{
// ERROR
}
break
;
case
I2C_R_OP
:
{
// send SLA+R
TWDR
=
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
read
.
address
<<
1
)
|
1
;
}
break
;
case
I2C_W_FLASH_OP
:
{
// send SLA+W
TWDR
=
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
write_flash
.
address
<<
1
);
}
break
;
case
I2C_W_RAM_OP
:
{
// send SLA+W
TWDR
=
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
write_ram
.
address
<<
1
);
}
break
;
case
I2C_W_1_OP
:
case
I2C_W_2_OP
:
case
I2C_W_3_OP
:
{
// send SLA+W
TWDR
=
(
i2c_ctx
.
transaction
[
i2c_ctx
.
pos
].
write
.
address
<<
1
);
}
break
;
}
twcr
=
0
;
data_pos
=
0
;
}
break
;
case
TW_MT_SLA_ACK
:
case
TW_MT_DATA_ACK
:
{
// Send next byte
if
(
i2c_more
(
data_pos
))
{
TWDR
=
i2c_get_data
(
data_pos
);
twcr
=
0
;
data_pos
++
;
}
else
{
if
(
i2c_next
())
{
// Repeated start
twcr
=
(
1
<<
TWSTA
);
}
else
{
// Done
twcr
=
(
1
<<
TWSTO
);
}
}
}
break
;
case
TW_MR_SLA_ACK
:
{
if
(
i2c_more
(
data_pos
+
1
))
{
// Receive byte, send ACK
twcr
=
(
1
<<
TWEA
);
}
else
{
// Receive last byte, send NOT ACK
twcr
=
0
;
}
}
break
;
case
TW_MR_DATA_ACK
:
case
TW_MR_DATA_NACK
:
{
// Data received:
i2c_put_data
(
data_pos
,
TWDR
);
data_pos
++
;
if
(
i2c_more
(
data_pos
+
1
))
{
// Receive byte, send ACK
twcr
=
(
1
<<
TWEA
);
}
else
if
(
i2c_more
(
data_pos
))
{
// Receive last byte, send NOT ACK
twcr
=
0
;
}
else
if
(
i2c_next
())
{
// Send repeated START
twcr
=
(
1
<<
TWSTA
);
}
else
{
// Send STOP
twcr
=
(
1
<<
TWSTO
);
}
}
break
;
default:
{
i2c_ctx
.
status
=
TW_STATUS
|
0x01
;
twcr
=
(
1
<<
TWSTO
);
// Done
#if 0
putstr("TWSR: ");
puthex(TW_STATUS);
putstr(" TWCR: ");
puthex(twcr);
putstr("\r\n");
#endif
}
break
;
}
#if 0
putstr("TWSR: ");
puthex(TW_STATUS);
putstr(" TWCR: ");
puthex(twcr);
putstr("\r\n");
#endif
TWCR
=
twcr
|
(
1
<<
TWINT
)
|
(
1
<<
TWEN
)
|
(
1
<<
TWIE
);
}
#endif
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment