Skip to content

Commit b81237a

Browse files
committed
init
0 parents  commit b81237a

File tree

7 files changed

+476
-0
lines changed

7 files changed

+476
-0
lines changed

Makefile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
3+
# project subdirectory.
4+
#
5+
6+
PROJECT_NAME := ulp-i2c
7+
8+
include $(IDF_PATH)/make/project.mk
9+

README.md

Whitespace-only changes.

main/component.mk

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# ULP support additions to component makefile.
3+
#
4+
# 1. ULP_APP_NAME must be unique (if multiple components use ULP)
5+
# Default value, override if necessary:
6+
ULP_APP_NAME ?= ulp_$(COMPONENT_NAME)
7+
#
8+
# 2. Specify all assembly source files here.
9+
# Files should be placed into a separate directory (in this case, ulp/),
10+
# which should not be added to COMPONENT_SRCDIRS.
11+
ULP_S_SOURCES = $(addprefix $(COMPONENT_PATH)/ulp/, \
12+
i2c.S \
13+
i2c-bmp180.S \
14+
)
15+
#
16+
# 3. List all the component object files which include automatically
17+
# generated ULP export file, $(ULP_APP_NAME).h:
18+
ULP_EXP_DEP_OBJECTS := ulp_example_main.o
19+
#
20+
# 4. Include build rules for ULP program
21+
include $(IDF_PATH)/components/ulp/component_ulp_common.mk
22+
#
23+
# Link object files and generate map file
24+
$(ULP_ELF): $(ULP_OBJECTS) $(ULP_LD_SCRIPT)
25+
$(summary) ULP_LD $(patsubst $(PWD)/%,%,$(CURDIR))/$@
26+
$(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(ULP_MAP) -T $(ULP_LD_SCRIPT) $(ULP_OBJECTS)
27+
#
28+
# End of ULP support additions to component makefile.
29+
#

main/ulp/i2c-bmp180.S

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Demo of I2C ULP routines
3+
*/
4+
5+
#include "soc/rtc_cntl_reg.h"
6+
#include "soc/rtc_io_reg.h"
7+
#include "soc/soc_ulp.h"
8+
9+
#include "stack.S"
10+
11+
.set BMP180_ADDR,0x77 // 7-bit address
12+
.set WRITE,((BMP180_ADDR << 1) | 0)
13+
.set READ,((BMP180_ADDR << 1) | 1)
14+
15+
.set BMP180_REG_CONTROL,0xF4
16+
.set BMP180_REG_RESULT,0xF6
17+
18+
.set BMP180_COMMAND_TEMPERATURE,0x2E
19+
.set BMP180_COMMAND_PRESSURE0,0x34
20+
.set BMP180_COMMAND_PRESSURE1,0x74
21+
.set BMP180_COMMAND_PRESSURE2,0xB4
22+
.set BMP180_COMMAND_PRESSURE3,0xF4
23+
24+
.macro status s
25+
move r1,status
26+
move r0,\s
27+
st r0,r1,0
28+
.endm
29+
30+
/* Define variables, which go into .bss section (zero-initialized data) */
31+
.bss
32+
.global status
33+
status: .long 0
34+
35+
.global stack
36+
stack:
37+
.skip 100
38+
.global stackEnd
39+
stackEnd:
40+
.long 0
41+
42+
/* Code goes into .text section */
43+
.text
44+
.global entry
45+
entry:
46+
move r3,stackEnd
47+
48+
status 1
49+
50+
wait 100
51+
psr
52+
jump i2c_start_cond
53+
54+
move r2,WRITE
55+
psr
56+
jump i2c_write_byte
57+
jumpr fail,1,ge
58+
59+
status 2
60+
61+
move r2,BMP180_REG_CONTROL
62+
psr
63+
jump i2c_write_byte
64+
65+
move r2,BMP180_COMMAND_TEMPERATURE
66+
psr
67+
jump i2c_write_byte
68+
69+
psr
70+
jump i2c_stop_cond
71+
72+
move r2,5
73+
psr
74+
jump waitMs
75+
76+
psr
77+
jump i2c_start_cond
78+
79+
move r2,WRITE
80+
psr
81+
jump i2c_write_byte
82+
83+
move r2,BMP180_REG_RESULT
84+
psr
85+
jump i2c_write_byte
86+
87+
psr
88+
jump i2c_start_cond
89+
90+
move r2,READ
91+
psr
92+
jump i2c_write_byte
93+
94+
move r2,0
95+
psr
96+
jump i2c_read_byte
97+
98+
move r2,1 // last byte
99+
psr
100+
jump i2c_read_byte
101+
102+
psr
103+
jump i2c_stop_cond
104+
105+
wait 100
106+
107+
fail:
108+
wake_up:
109+
/* Wake up the SoC, end program */
110+
wake
111+
halt
112+
113+
waitMs:
114+
wait 8000
115+
sub r2,r2,1
116+
jump doneWaitMs,eq
117+
jump waitMs
118+
doneWaitMs:
119+
ret

main/ulp/i2c.S

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* Demo of I2C ULP routines
3+
*/
4+
5+
#include "soc/rtc_cntl_reg.h"
6+
#include "soc/rtc_io_reg.h"
7+
#include "soc/soc_ulp.h"
8+
9+
#include "stack.S"
10+
11+
12+
/*
13+
* =============================== I2C code ==========================================
14+
* Implementation of pseudo code from
15+
* https://en.wikipedia.org/wiki/I%C2%B2C#Example_of_bit-banging_the_I.C2.B2C_master_protocol
16+
*/
17+
18+
.bss
19+
i2c_started:
20+
.long 0
21+
22+
.text
23+
24+
.global i2c_start_cond
25+
.global i2c_stop_cond
26+
.global i2c_write_bit
27+
.global i2c_read_bit
28+
.global i2c_write_byte
29+
.global i2c_read_byte
30+
31+
.macro I2C_delay
32+
wait 38 // minimal 4.7us
33+
.endm
34+
35+
.macro read_SCL // Return current level of SCL line, 0 or 1
36+
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + 9, 1) // RTC_GPIO_9 == GPIO_32
37+
.endm
38+
39+
.macro read_SDA // Return current level of SDA line, 0 or 1
40+
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + 8, 1) // RTC_GPIO_8 == GPIO_33
41+
.endm
42+
43+
.macro set_SCL // Do not drive SCL (set pin high-impedance)
44+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + 9, 1, 1)
45+
.endm
46+
47+
.macro clear_SCL // Actively drive SCL signal low
48+
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + 9, 1, 0)
49+
// Output mode
50+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + 9, 1, 1)
51+
.endm
52+
53+
.macro set_SDA // Do not drive SDA (set pin high-impedance)
54+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + 8, 1, 1)
55+
.endm
56+
57+
.macro clear_SDA // Actively drive SDA signal low
58+
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + 8, 1, 0)
59+
// Output mode
60+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + 8, 1, 1)
61+
.endm
62+
63+
64+
i2c_start_cond:
65+
move r2,i2c_started
66+
ld r0,r2,0
67+
jumpr not_started,1,ge
68+
// if started, do a restart condition
69+
// set SDA to 1
70+
set_SDA
71+
I2C_delay
72+
set_SCL
73+
clock_stretch: // TODO: Add timeout?
74+
read_SCL
75+
jumpr clock_stretch,1,lt
76+
77+
// Repeated start setup time, minimum 4.7us
78+
I2C_delay
79+
80+
not_started:
81+
// if (read_SDA() == 0) {
82+
// arbitration_lost();
83+
// }
84+
85+
// SCL is high, set SDA from 1 to 0.
86+
clear_SDA
87+
I2C_delay
88+
clear_SCL
89+
move r0,1
90+
st r0,r2,0
91+
92+
ret
93+
94+
95+
i2c_stop_cond:
96+
// set SDA to 0
97+
clear_SDA
98+
I2C_delay
99+
100+
set_SCL
101+
clock_stretch_stop:
102+
read_SCL
103+
jumpr clock_stretch_stop,1,lt
104+
105+
// Stop bit setup time, minimum 4us
106+
I2C_delay
107+
// if (read_SDA() == 0) {
108+
// arbitration_lost();
109+
// }
110+
111+
move r2,i2c_started
112+
move r0,0
113+
st r0,r2,0
114+
115+
ret
116+
117+
118+
// Write a bit to I2C bus
119+
i2c_write_bit:
120+
jumpr bit0,1,lt
121+
set_SDA
122+
jump bit1
123+
bit0:
124+
clear_SDA
125+
bit1:
126+
127+
// SDA change propagation delay
128+
I2C_delay
129+
// Set SCL high to indicate a new valid SDA value is available
130+
set_SCL
131+
// Wait for SDA value to be read by slave, minimum of 4us for standard mode
132+
I2C_delay
133+
134+
clock_stretch_write:
135+
read_SCL
136+
jumpr clock_stretch_write,1,lt
137+
138+
// SCL is high, now data is valid
139+
// If SDA is high, check that nobody else is driving SDA
140+
// if (bit && (read_SDA() == 0)) {
141+
// arbitration_lost();
142+
// }
143+
144+
// Clear the SCL to low in preparation for next change
145+
clear_SCL
146+
147+
ret
148+
149+
150+
// Read a bit from I2C bus
151+
i2c_read_bit:
152+
// Let the slave drive data
153+
set_SDA
154+
// Wait for SDA value to be written by slave, minimum of 4us for standard mode
155+
I2C_delay
156+
// Set SCL high to indicate a new valid SDA value is available
157+
set_SCL
158+
159+
clock_stretch_read:
160+
read_SCL
161+
jumpr clock_stretch_read,1,lt
162+
163+
// Wait for SDA value to be written by slave, minimum of 4us for standard mode
164+
I2C_delay
165+
// SCL is high, read out bit
166+
read_SDA
167+
// Set SCL low in preparation for next operation
168+
clear_SCL
169+
170+
ret // bit in r0
171+
172+
// Write a byte to I2C bus. Return 0 if ack by the slave.
173+
i2c_write_byte:
174+
stage_rst
175+
next_bit:
176+
and r0,r2,0x80
177+
psr
178+
jump i2c_write_bit
179+
lsh r2,r2,1
180+
stage_inc 1
181+
jumps next_bit,8,lt
182+
183+
psr
184+
jump i2c_read_bit
185+
ret // nack
186+
187+
188+
// Read a byte from I2C bus
189+
i2c_read_byte:
190+
push r2
191+
move r2,0
192+
stage_rst
193+
next_bit_read:
194+
psr
195+
jump i2c_read_bit
196+
lsh r2,r2,1
197+
or r2,r2,r0
198+
stage_inc 1
199+
jumps next_bit_read,8,lt
200+
201+
pop r0
202+
psr
203+
jump i2c_write_bit
204+
205+
move r0,r2
206+
207+
ret
208+

main/ulp/stack.S

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* ULP stack and subroutine macros
3+
*/
4+
5+
.macro push rx
6+
st \rx,r3,0
7+
sub r3,r3,1
8+
.endm
9+
10+
.macro pop rx
11+
add r3,r3,1
12+
ld \rx,r3,0
13+
.endm
14+
15+
// Prepare subroutine jump, uses scratch register sr
16+
.macro psr sr=r1 pos=.
17+
.set _next2,(\pos+16)
18+
move \sr,_next2
19+
push \sr
20+
.endm
21+
22+
// Return from subroutine
23+
.macro ret sr=r1
24+
pop \sr
25+
jump \sr
26+
.endm

0 commit comments

Comments
 (0)