Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
M
micropython
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
card10
micropython
Commits
6474598c
Commit
6474598c
authored
11 years ago
by
Hagen Kaye
Browse files
Options
Downloads
Patches
Plain Diff
Added i2c python interface object
parent
b8ecc29f
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
stm/i2c.c
+364
-0
364 additions, 0 deletions
stm/i2c.c
stm/i2c.h
+1
-0
1 addition, 0 deletions
stm/i2c.h
with
365 additions
and
0 deletions
stm/i2c.c
0 → 100644
+
364
−
0
View file @
6474598c
#include
<stdio.h>
#include
<stm32f4xx.h>
#include
<stm32f4xx_rcc.h>
#include
<stm32f4xx_gpio.h>
#include
"misc.h"
#include
"systick.h"
#include
"mpconfig.h"
#include
"obj.h"
typedef
enum
{
PYB_I2C_1
=
0
,
PYB_I2C_2
=
1
,
}
pyb_i2c_t
;
typedef
enum
{
I2C_STATE_IDLE
=
0
,
I2C_STATE_WRITE
=
1
,
I2C_STATE_READ
=
2
,
}
i2c_state_t
;
// set to true if the port has already been initialized
bool
i2c1_port_initialized
=
false
;
bool
i2c2_port_initialized
=
false
;
static
I2C_TypeDef
*
_i2c_port_addr
(
pyb_i2c_t
i2c_port
)
{
if
(
i2c_port
==
PYB_I2C_1
)
return
I2C1
;
if
(
i2c_port
==
PYB_I2C_2
)
return
I2C2
;
return
NULL
;
}
// todo - perhaps there should be some global resource management for gpio
// this function would fail if the i2c pins have already been defined for
// use by another python object
// as it is, this always returns true (unless i2c_port is invalid)
static
bool
_i2c_init
(
pyb_i2c_t
i2c_port
)
{
GPIO_InitTypeDef
GPIO_InitStructure
;
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
false
;
if
(
i2c_port
==
PYB_I2C_1
)
{
if
(
i2c1_port_initialized
==
true
)
return
true
;
RCC
->
APB1ENR
|=
RCC_APB1ENR_I2C1EN
;
// enable I2C1
// PB6=SCL, PB7=SDA
GPIO_InitStructure
.
GPIO_Pin
=
GPIO_Pin_6
|
GPIO_Pin_7
;
GPIO_InitStructure
.
GPIO_Mode
=
GPIO_Mode_AF
;
GPIO_InitStructure
.
GPIO_OType
=
GPIO_OType_OD
;
GPIO_InitStructure
.
GPIO_Speed
=
GPIO_Speed_25MHz
;
GPIO_InitStructure
.
GPIO_PuPd
=
GPIO_PuPd_NOPULL
;
GPIO_Init
(
GPIOB
,
&
GPIO_InitStructure
);
// alternate functions for SCL and SDA
GPIO_PinAFConfig
(
GPIOB
,
GPIO_PinSource6
,
GPIO_AF_I2C1
);
GPIO_PinAFConfig
(
GPIOB
,
GPIO_PinSource7
,
GPIO_AF_I2C1
);
i2c1_port_initialized
=
true
;
}
if
(
i2c_port
==
PYB_I2C_2
)
{
if
(
i2c2_port_initialized
==
true
)
return
true
;
RCC
->
APB1ENR
|=
RCC_APB1ENR_I2C2EN
;
// enable I2C2
// PB10=SCL, PB11=SDA
GPIO_InitStructure
.
GPIO_Pin
=
GPIO_Pin_10
|
GPIO_Pin_11
;
GPIO_InitStructure
.
GPIO_Mode
=
GPIO_Mode_AF
;
GPIO_InitStructure
.
GPIO_OType
=
GPIO_OType_OD
;
GPIO_InitStructure
.
GPIO_Speed
=
GPIO_Speed_25MHz
;
GPIO_InitStructure
.
GPIO_PuPd
=
GPIO_PuPd_NOPULL
;
GPIO_Init
(
GPIOB
,
&
GPIO_InitStructure
);
// alternate functions for SCL and SDA
GPIO_PinAFConfig
(
GPIOB
,
GPIO_PinSource10
,
GPIO_AF_I2C2
);
GPIO_PinAFConfig
(
GPIOB
,
GPIO_PinSource11
,
GPIO_AF_I2C2
);
i2c2_port_initialized
=
true
;
}
// get clock speeds
RCC_ClocksTypeDef
rcc_clocks
;
RCC_GetClocksFreq
(
&
rcc_clocks
);
// disable the I2C peripheral before we configure it
i2c
->
CR1
&=
~
I2C_CR1_PE
;
// program peripheral input clock
i2c
->
CR2
=
4
;
// no interrupts; 4 MHz (hopefully!) (could go up to 42MHz)
// configure clock control reg
uint32_t
freq
=
rcc_clocks
.
PCLK1_Frequency
/
(
100000
<<
1
);
// want 100kHz, this is the formula for freq
i2c
->
CCR
=
freq
;
// standard mode (speed), freq calculated as above
// configure rise time reg
i2c
->
TRISE
=
(
rcc_clocks
.
PCLK1_Frequency
/
1000000
)
+
1
;
// formula for trise, gives maximum rise time
// enable the I2C peripheral
i2c
->
CR1
|=
I2C_CR1_PE
;
return
true
;
}
static
uint32_t
_i2c_get_sr
(
pyb_i2c_t
i2c_port
)
{
// must read SR1 first, then SR2, as the read can clear some flags
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
0
;
uint32_t
sr1
=
i2c
->
SR1
;
uint32_t
sr2
=
i2c
->
SR2
;
return
(
sr2
<<
16
)
|
sr1
;
}
static
bool
_i2c_restart
(
pyb_i2c_t
i2c_port
,
uint8_t
addr
,
int
write
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
false
;
// send start condition
i2c
->
CR1
|=
I2C_CR1_START
;
// wait for BUSY, MSL and SB --> Slave has acknowledged start condition
uint32_t
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00030001
)
!=
0x00030001
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_restart\n");
return
false
;
}
}
if
(
write
)
{
// send address and write bit
i2c
->
DR
=
(
addr
<<
1
)
|
0
;
// wait for BUSY, MSL, ADDR, TXE and TRA
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00070082
)
!=
0x00070082
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_restart write\n");
return
false
;
}
}
}
else
{
// send address and read bit
i2c
->
DR
=
(
addr
<<
1
)
|
1
;
// wait for BUSY, MSL and ADDR flags
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00030002
)
!=
0x00030002
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_restart read\n");
return
false
;
}
}
}
return
true
;
}
static
bool
_i2c_send_byte
(
pyb_i2c_t
i2c_port
,
uint8_t
data
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
false
;
// send byte
i2c
->
DR
=
data
;
// wait for TRA, BUSY, MSL, TXE and BTF (byte transmitted)
uint32_t
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00070084
)
!=
0x00070084
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_send_byte\n");
return
false
;
}
}
return
true
;
}
static
uint8_t
_i2c_read_ack
(
pyb_i2c_t
i2c_port
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
0
;
// enable ACK of received byte
i2c
->
CR1
|=
I2C_CR1_ACK
;
// wait for BUSY, MSL and RXNE (byte received)
uint32_t
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00030040
)
!=
0x00030040
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_read_ack\n");
break
;
}
}
// read and return data
uint8_t
data
=
i2c
->
DR
;
return
data
;
}
static
uint8_t
_i2c_read_nack
(
pyb_i2c_t
i2c_port
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
0
;
// disable ACK of received byte (to indicate end of receiving)
i2c
->
CR1
&=
(
uint16_t
)
~
((
uint16_t
)
I2C_CR1_ACK
);
// last byte should apparently also generate a stop condition
i2c
->
CR1
|=
I2C_CR1_STOP
;
// wait for BUSY, MSL and RXNE (byte received)
uint32_t
timeout
=
1000000
;
while
((
_i2c_get_sr
(
i2c_port
)
&
0x00030040
)
!=
0x00030040
)
{
if
(
--
timeout
==
0
)
{
//printf("timeout in _i2c_read_nack\n");
break
;
}
}
// read and return data
uint8_t
data
=
i2c
->
DR
;
return
data
;
}
static
bool
_i2c_start
(
pyb_i2c_t
i2c_port
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
false
;
// wait until I2C is not busy
uint32_t
timeout
=
1000000
;
while
(
i2c
->
SR2
&
I2C_SR2_BUSY
)
{
if
(
--
timeout
==
0
)
{
return
false
;
}
}
return
true
;
}
static
void
_i2c_stop
(
pyb_i2c_t
i2c_port
)
{
I2C_TypeDef
*
i2c
=
_i2c_port_addr
(
i2c_port
);
if
(
i2c
==
NULL
)
return
;
// send stop condition
i2c
->
CR1
|=
I2C_CR1_STOP
;
}
/******************************************************************************/
/* Micro Python bindings */
typedef
struct
_pyb_i2c_obj_t
{
mp_obj_base_t
base
;
pyb_i2c_t
i2c_port
;
int
i2c_addr
;
i2c_state_t
i2c_state
;
}
pyb_i2c_obj_t
;
void
i2c_obj_print
(
void
(
*
print
)(
void
*
env
,
const
char
*
fmt
,
...),
void
*
env
,
mp_obj_t
self_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
print
(
env
,
"<I2C%lu addr:%lu>"
,
(
unsigned
int
)
self
->
i2c_port
,
(
unsigned
int
)
self
->
i2c_addr
);
}
// calls _i2c_start with write=0,1 depending on LSB of i2c_addr
mp_obj_t
i2c_obj_start
(
mp_obj_t
self_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
if
(
self
->
i2c_state
!=
I2C_STATE_IDLE
)
{
_i2c_stop
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
}
if
(
_i2c_start
(
self
->
i2c_port
)
==
true
)
return
mp_const_true
;
return
mp_const_false
;
}
mp_obj_t
i2c_obj_write
(
mp_obj_t
self_in
,
mp_obj_t
data_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
if
(
self
->
i2c_state
!=
I2C_STATE_WRITE
)
{
if
(
_i2c_restart
(
self
->
i2c_port
,
self
->
i2c_addr
,
1
)
==
false
)
{
_i2c_stop
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
return
mp_const_false
;
}
self
->
i2c_state
=
I2C_STATE_WRITE
;
}
uint8_t
data
=
mp_obj_get_int
(
data_in
);
if
(
_i2c_send_byte
(
self
->
i2c_port
,
data
)
==
false
)
return
mp_const_false
;
return
mp_const_true
;
}
mp_obj_t
i2c_obj_read
(
mp_obj_t
self_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
if
(
self
->
i2c_state
!=
I2C_STATE_READ
)
{
if
(
_i2c_restart
(
self
->
i2c_port
,
self
->
i2c_addr
,
0
)
==
false
)
{
_i2c_stop
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
return
mp_const_false
;
}
self
->
i2c_state
=
I2C_STATE_READ
;
}
uint8_t
data
=
_i2c_read_ack
(
self
->
i2c_port
);
return
mp_obj_new_int
(
data
);
}
mp_obj_t
i2c_obj_readAndStop
(
mp_obj_t
self_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
if
(
self
->
i2c_state
!=
I2C_STATE_READ
)
{
if
(
_i2c_restart
(
self
->
i2c_port
,
self
->
i2c_addr
,
0
)
==
false
)
{
_i2c_stop
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
return
mp_const_false
;
}
}
uint8_t
data
=
_i2c_read_nack
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
return
mp_obj_new_int
(
data
);
}
mp_obj_t
i2c_obj_stop
(
mp_obj_t
self_in
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
_i2c_stop
(
self
->
i2c_port
);
self
->
i2c_state
=
I2C_STATE_IDLE
;
return
mp_const_none
;
}
static
MP_DEFINE_CONST_FUN_OBJ_1
(
i2c_obj_start_obj
,
i2c_obj_start
);
static
MP_DEFINE_CONST_FUN_OBJ_2
(
i2c_obj_write_obj
,
i2c_obj_write
);
static
MP_DEFINE_CONST_FUN_OBJ_1
(
i2c_obj_read_obj
,
i2c_obj_read
);
static
MP_DEFINE_CONST_FUN_OBJ_1
(
i2c_obj_readAndStop_obj
,
i2c_obj_readAndStop
);
static
MP_DEFINE_CONST_FUN_OBJ_1
(
i2c_obj_stop_obj
,
i2c_obj_stop
);
static
const
mp_obj_type_t
i2c_obj_type
=
{
{
&
mp_const_type
},
"I2C"
,
i2c_obj_print
,
// print
NULL
,
// call_n
NULL
,
// unary_op
NULL
,
// binary_op
NULL
,
// getiter
NULL
,
// iternext
{
// method list
{
"start"
,
&
i2c_obj_start_obj
},
{
"write"
,
&
i2c_obj_write_obj
},
{
"read"
,
&
i2c_obj_read_obj
},
{
"readAndStop"
,
&
i2c_obj_readAndStop_obj
},
{
"stop"
,
&
i2c_obj_stop_obj
},
{
NULL
,
NULL
},
}
};
// create the I2C object
// currently support either I2C1 (i2c_id = 0) or I2C2 (i2c_id = 1)
mp_obj_t
pyb_I2C
(
mp_obj_t
i2c_id
,
mp_obj_t
i2c_addr
)
{
pyb_i2c_t
i2c_port
;
switch
(
mp_obj_get_int
(
i2c_id
))
{
case
0
:
i2c_port
=
PYB_I2C_1
;
break
;
case
1
:
i2c_port
=
PYB_I2C_2
;
break
;
default:
return
mp_const_none
;
}
if
(
_i2c_init
(
i2c_port
)
==
false
)
return
mp_const_none
;
pyb_i2c_obj_t
*
o
=
m_new_obj
(
pyb_i2c_obj_t
);
o
->
base
.
type
=
&
i2c_obj_type
;
o
->
i2c_port
=
i2c_port
;
o
->
i2c_addr
=
mp_obj_get_int
(
i2c_addr
);
o
->
i2c_state
=
I2C_STATE_IDLE
;
return
o
;
}
This diff is collapsed.
Click to expand it.
stm/i2c.h
0 → 100644
+
1
−
0
View file @
6474598c
mp_obj_t
pyb_I2C
(
mp_obj_t
i2c_id
,
mp_obj_t
i2c_addr
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment