Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
76285469
Commit
76285469
authored
Jun 10, 2015
by
Damien George
Browse files
stmhal: Make I2C use DMA when interrupts are enabled.
parent
3d30d605
Changes
1
Hide whitespace changes
Inline
Side-by-side
stmhal/i2c.c
View file @
76285469
...
...
@@ -29,9 +29,11 @@
#include
"py/nlr.h"
#include
"py/runtime.h"
#include
"irq.h"
#include
"pin.h"
#include
"genhdr/pins.h"
#include
"bufhelper.h"
#include
"dma.h"
#include
"i2c.h"
#include MICROPY_HAL_H
...
...
@@ -84,9 +86,26 @@
/// # starting at address 2 in the slave
/// i2c.mem_write('abc', 0x42, 2, timeout=1000)
// Possible DMA configurations for I2C busses:
// I2C1_TX: DMA1_Stream6.CHANNEL_1 or DMA1_Stream7.CHANNEL_1
// I2C1_RX: DMA1_Stream0.CHANNEL_1 or DMA1_Stream5.CHANNEL_1
// I2C2_TX: DMA1_Stream7.CHANNEL_7
// I2C2_RX: DMA1_Stream2.CHANNEL_7 or DMA1_Stream3.CHANNEL_7
// I2C3_TX: DMA1_Stream4.CHANNEL_3
// I2C3_RX: DMA1_Stream2.CHANNEL_3
#define PYB_I2C_MASTER (0)
#define PYB_I2C_SLAVE (1)
typedef
struct
_pyb_i2c_obj_t
{
mp_obj_base_t
base
;
I2C_HandleTypeDef
*
i2c
;
DMA_Stream_TypeDef
*
tx_dma_stream
;
uint32_t
tx_dma_channel
;
DMA_Stream_TypeDef
*
rx_dma_stream
;
uint32_t
rx_dma_channel
;
}
pyb_i2c_obj_t
;
#if defined(MICROPY_HW_I2C1_SCL)
I2C_HandleTypeDef
I2CHandle1
=
{.
Instance
=
NULL
};
#endif
...
...
@@ -97,6 +116,24 @@ I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
I2C_HandleTypeDef
I2CHandle3
=
{.
Instance
=
NULL
};
#endif
STATIC
const
pyb_i2c_obj_t
pyb_i2c_obj
[]
=
{
#if defined(MICROPY_HW_I2C1_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle1
,
DMA1_Stream7
,
DMA_CHANNEL_1
,
DMA1_Stream0
,
DMA_CHANNEL_1
},
#else
{{
&
pyb_i2c_type
},
NULL
,
NULL
,
0
,
NULL
,
0
},
#endif
#if defined(MICROPY_HW_I2C2_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle2
,
DMA1_Stream7
,
DMA_CHANNEL_7
,
DMA1_Stream2
,
DMA_CHANNEL_7
},
#else
{{
&
pyb_i2c_type
},
NULL
,
NULL
,
0
,
NULL
,
0
},
#endif
#if defined(MICROPY_HW_I2C3_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle3
,
DMA1_Stream4
,
DMA_CHANNEL_3
,
DMA1_Stream2
,
DMA_CHANNEL_3
},
#else
{{
&
pyb_i2c_type
},
NULL
,
NULL
,
0
,
NULL
,
0
},
#endif
};
void
i2c_init0
(
void
)
{
// reset the I2C1 handles
#if defined(MICROPY_HW_I2C1_SCL)
...
...
@@ -120,10 +157,13 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
GPIO_InitStructure
.
Speed
=
GPIO_SPEED_FAST
;
GPIO_InitStructure
.
Pull
=
GPIO_NOPULL
;
// have external pull-up resistors on both lines
const
pyb_i2c_obj_t
*
self
;
const
pin_obj_t
*
pins
[
2
];
if
(
0
)
{
#if defined(MICROPY_HW_I2C1_SCL)
}
else
if
(
i2c
==
&
I2CHandle1
)
{
self
=
&
pyb_i2c_obj
[
0
];
pins
[
0
]
=
&
MICROPY_HW_I2C1_SCL
;
pins
[
1
]
=
&
MICROPY_HW_I2C1_SDA
;
GPIO_InitStructure
.
Alternate
=
GPIO_AF4_I2C1
;
...
...
@@ -131,6 +171,7 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
#endif
#if defined(MICROPY_HW_I2C2_SCL)
}
else
if
(
i2c
==
&
I2CHandle2
)
{
self
=
&
pyb_i2c_obj
[
1
];
pins
[
0
]
=
&
MICROPY_HW_I2C2_SCL
;
pins
[
1
]
=
&
MICROPY_HW_I2C2_SDA
;
GPIO_InitStructure
.
Alternate
=
GPIO_AF4_I2C2
;
...
...
@@ -138,6 +179,7 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
#endif
#if defined(MICROPY_HW_I2C3_SCL)
}
else
if
(
i2c
==
&
I2CHandle3
)
{
self
=
&
pyb_i2c_obj
[
2
];
pins
[
0
]
=
&
MICROPY_HW_I2C3_SCL
;
pins
[
1
]
=
&
MICROPY_HW_I2C3_SDA
;
GPIO_InitStructure
.
Alternate
=
GPIO_AF4_I2C3
;
...
...
@@ -162,6 +204,10 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
printf
(
"OSError: HAL_I2C_Init failed
\n
"
);
return
;
}
// invalidate the DMA channels so they are initialised on first use
dma_invalidate_channel
(
self
->
tx_dma_stream
,
self
->
tx_dma_channel
);
dma_invalidate_channel
(
self
->
rx_dma_stream
,
self
->
rx_dma_channel
);
}
void
i2c_deinit
(
I2C_HandleTypeDef
*
i2c
)
{
...
...
@@ -188,34 +234,24 @@ void i2c_deinit(I2C_HandleTypeDef *i2c) {
}
}
STATIC
HAL_StatusTypeDef
i2c_wait_dma_finished
(
I2C_HandleTypeDef
*
i2c
,
uint32_t
timeout
)
{
// Note: we can't use WFI to idle in this loop because the DMA completion
// interrupt may occur before the WFI. Hence we miss it and have to wait
// until the next sys-tick (up to 1ms).
uint32_t
start
=
HAL_GetTick
();
while
(
HAL_I2C_GetState
(
i2c
)
!=
HAL_I2C_STATE_READY
)
{
if
(
HAL_GetTick
()
-
start
>=
timeout
)
{
return
HAL_TIMEOUT
;
}
}
return
HAL_OK
;
}
/******************************************************************************/
/* Micro Python bindings */
typedef
struct
_pyb_i2c_obj_t
{
mp_obj_base_t
base
;
I2C_HandleTypeDef
*
i2c
;
}
pyb_i2c_obj_t
;
STATIC
inline
bool
in_master_mode
(
pyb_i2c_obj_t
*
self
)
{
return
self
->
i2c
->
Init
.
OwnAddress1
==
PYB_I2C_MASTER_ADDRESS
;
}
STATIC
const
pyb_i2c_obj_t
pyb_i2c_obj
[]
=
{
#if defined(MICROPY_HW_I2C1_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle1
},
#else
{{
&
pyb_i2c_type
},
NULL
},
#endif
#if defined(MICROPY_HW_I2C2_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle2
},
#else
{{
&
pyb_i2c_type
},
NULL
},
#endif
#if defined(MICROPY_HW_I2C3_SCL)
{{
&
pyb_i2c_type
},
&
I2CHandle3
},
#else
{{
&
pyb_i2c_type
},
NULL
},
#endif
};
STATIC
void
pyb_i2c_print
(
const
mp_print_t
*
print
,
mp_obj_t
self_in
,
mp_print_kind_t
kind
)
{
pyb_i2c_obj_t
*
self
=
self_in
;
...
...
@@ -435,16 +471,43 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
uint8_t
data
[
1
];
pyb_buf_get_for_send
(
vals
[
0
].
u_obj
,
&
bufinfo
,
data
);
// if IRQs are enabled then we can use DMA
DMA_HandleTypeDef
tx_dma
;
if
(
query_irq
()
==
IRQ_STATE_ENABLED
)
{
dma_init
(
&
tx_dma
,
self
->
tx_dma_stream
,
self
->
tx_dma_channel
,
DMA_MEMORY_TO_PERIPH
,
self
->
i2c
);
self
->
i2c
->
hdmatx
=
&
tx_dma
;
self
->
i2c
->
hdmarx
=
NULL
;
}
// send the data
HAL_StatusTypeDef
status
;
if
(
in_master_mode
(
self
))
{
if
(
vals
[
1
].
u_int
==
PYB_I2C_MASTER_ADDRESS
)
{
if
(
query_irq
()
==
IRQ_STATE_ENABLED
)
{
dma_deinit
(
&
tx_dma
);
}
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_TypeError
,
"addr argument required"
));
}
mp_uint_t
i2c_addr
=
vals
[
1
].
u_int
<<
1
;
status
=
HAL_I2C_Master_Transmit
(
self
->
i2c
,
i2c_addr
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
2
].
u_int
);
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Master_Transmit
(
self
->
i2c
,
i2c_addr
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
2
].
u_int
);
}
else
{
status
=
HAL_I2C_Master_Transmit_DMA
(
self
->
i2c
,
i2c_addr
,
bufinfo
.
buf
,
bufinfo
.
len
);
}
}
else
{
status
=
HAL_I2C_Slave_Transmit
(
self
->
i2c
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
2
].
u_int
);
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Slave_Transmit
(
self
->
i2c
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
2
].
u_int
);
}
else
{
status
=
HAL_I2C_Slave_Transmit_DMA
(
self
->
i2c
,
bufinfo
.
buf
,
bufinfo
.
len
);
}
}
// if we used DMA, wait for it to finish
if
(
query_irq
()
==
IRQ_STATE_ENABLED
)
{
if
(
status
==
HAL_OK
)
{
status
=
i2c_wait_dma_finished
(
self
->
i2c
,
vals
[
2
].
u_int
);
}
dma_deinit
(
&
tx_dma
);
}
if
(
status
!=
HAL_OK
)
{
...
...
@@ -484,6 +547,14 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
vstr_t
vstr
;
mp_obj_t
o_ret
=
pyb_buf_get_for_recv
(
vals
[
0
].
u_obj
,
&
vstr
);
// if IRQs are enabled then we can use DMA
DMA_HandleTypeDef
rx_dma
;
if
(
query_irq
()
==
IRQ_STATE_ENABLED
)
{
dma_init
(
&
rx_dma
,
self
->
rx_dma_stream
,
self
->
rx_dma_channel
,
DMA_PERIPH_TO_MEMORY
,
self
->
i2c
);
self
->
i2c
->
hdmatx
=
NULL
;
self
->
i2c
->
hdmarx
=
&
rx_dma
;
}
// receive the data
HAL_StatusTypeDef
status
;
if
(
in_master_mode
(
self
))
{
...
...
@@ -491,9 +562,25 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_TypeError
,
"addr argument required"
));
}
mp_uint_t
i2c_addr
=
vals
[
1
].
u_int
<<
1
;
status
=
HAL_I2C_Master_Receive
(
self
->
i2c
,
i2c_addr
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
2
].
u_int
);
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Master_Receive
(
self
->
i2c
,
i2c_addr
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
2
].
u_int
);
}
else
{
status
=
HAL_I2C_Master_Receive_DMA
(
self
->
i2c
,
i2c_addr
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
);
}
}
else
{
status
=
HAL_I2C_Slave_Receive
(
self
->
i2c
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
2
].
u_int
);
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Slave_Receive
(
self
->
i2c
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
2
].
u_int
);
}
else
{
status
=
HAL_I2C_Slave_Receive_DMA
(
self
->
i2c
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
);
}
}
// if we used DMA, wait for it to finish
if
(
query_irq
()
==
IRQ_STATE_ENABLED
)
{
if
(
status
==
HAL_OK
)
{
status
=
i2c_wait_dma_finished
(
self
->
i2c
,
vals
[
2
].
u_int
);
}
dma_deinit
(
&
rx_dma
);
}
if
(
status
!=
HAL_OK
)
{
...
...
@@ -554,7 +641,20 @@ STATIC mp_obj_t pyb_i2c_mem_read(mp_uint_t n_args, const mp_obj_t *args, mp_map_
mem_addr_size
=
I2C_MEMADD_SIZE_16BIT
;
}
HAL_StatusTypeDef
status
=
HAL_I2C_Mem_Read
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
3
].
u_int
);
HAL_StatusTypeDef
status
;
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Mem_Read
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
,
vals
[
3
].
u_int
);
}
else
{
DMA_HandleTypeDef
rx_dma
;
dma_init
(
&
rx_dma
,
self
->
rx_dma_stream
,
self
->
rx_dma_channel
,
DMA_PERIPH_TO_MEMORY
,
self
->
i2c
);
self
->
i2c
->
hdmatx
=
NULL
;
self
->
i2c
->
hdmarx
=
&
rx_dma
;
status
=
HAL_I2C_Mem_Read_DMA
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
(
uint8_t
*
)
vstr
.
buf
,
vstr
.
len
);
if
(
status
==
HAL_OK
)
{
status
=
i2c_wait_dma_finished
(
self
->
i2c
,
vals
[
3
].
u_int
);
}
dma_deinit
(
&
rx_dma
);
}
if
(
status
!=
HAL_OK
)
{
mp_hal_raise
(
status
);
...
...
@@ -606,7 +706,20 @@ STATIC mp_obj_t pyb_i2c_mem_write(mp_uint_t n_args, const mp_obj_t *args, mp_map
mem_addr_size
=
I2C_MEMADD_SIZE_16BIT
;
}
HAL_StatusTypeDef
status
=
HAL_I2C_Mem_Write
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
3
].
u_int
);
HAL_StatusTypeDef
status
;
if
(
query_irq
()
==
IRQ_STATE_DISABLED
)
{
status
=
HAL_I2C_Mem_Write
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
bufinfo
.
buf
,
bufinfo
.
len
,
vals
[
3
].
u_int
);
}
else
{
DMA_HandleTypeDef
tx_dma
;
dma_init
(
&
tx_dma
,
self
->
tx_dma_stream
,
self
->
tx_dma_channel
,
DMA_MEMORY_TO_PERIPH
,
self
->
i2c
);
self
->
i2c
->
hdmatx
=
&
tx_dma
;
self
->
i2c
->
hdmarx
=
NULL
;
status
=
HAL_I2C_Mem_Write_DMA
(
self
->
i2c
,
i2c_addr
,
mem_addr
,
mem_addr_size
,
bufinfo
.
buf
,
bufinfo
.
len
);
if
(
status
==
HAL_OK
)
{
status
=
i2c_wait_dma_finished
(
self
->
i2c
,
vals
[
3
].
u_int
);
}
dma_deinit
(
&
tx_dma
);
}
if
(
status
!=
HAL_OK
)
{
mp_hal_raise
(
status
);
...
...
Write
Preview
Supports
Markdown
0%
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!
Cancel
Please
register
or
sign in
to comment