Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
Skyward Boardcore
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
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Nicolò Caruso
Skyward Boardcore
Commits
250c761c
Commit
250c761c
authored
2 years ago
by
EmilioCorigliano
Committed by
Alberto Nidasio
2 years ago
Browse files
Options
Downloads
Patches
Plain Diff
[I2C] Added and updated documentation
parent
917967b9
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/shared/drivers/i2c/I2CDriver-f7.cpp
+44
-22
44 additions, 22 deletions
src/shared/drivers/i2c/I2CDriver-f7.cpp
with
44 additions
and
22 deletions
src/shared/drivers/i2c/I2CDriver-f7.cpp
+
44
−
22
View file @
250c761c
...
...
@@ -63,15 +63,24 @@ static uint8_t SDADEL_FP; ///< SDADEL for FAST PLUS speed
/**
* @brief Helper function for calculating the timing parameters for the
* peripheral
*
* The formula for the clock is:
* t_SCL = [(SCLL + 1) + (SCLH + 1)] * (PRESC + 1) * t_I2CCLK + t_sync
* @param f Peripheral timer clock frequency in kHz
* @param fi2c I2C clock frequency in kHz
* @param presc pointer to the prescaler variable to set
* @param sclh pointer to the sclh variable to set
* @param scll pointer to the scll variable to set
* @param scldel pointer to the scldel variable to set
* @param sdadel pointer to the sdadel variable to set
*/
void
calculateTimings
(
uint32_t
f
,
uint32_t
fi2c
,
uint8_t
*
presc
,
uint8_t
*
sclh
,
uint8_t
*
scll
,
uint8_t
*
scldel
,
uint8_t
*
sdadel
)
{
// The formula for the clock is:
// t_SCL = [(SCLL + 1) + (SCLH + 1)] * (PRESC + 1) * t_I2CCLK + t_sync;
// calculating the "smallest" prescaler so that we can handle in a more
// refined way (with SCLL and SCLH) the length of high and low phases.
// refined way (with SCLL and SCLH) the length of high and low phases. We
// "limit" SCLL and SCLH to 64 because like so we can have acceptable values
// for SCLDEL and SDADEL
uint32_t
temp_presc
=
f
/
(
64
*
fi2c
);
// presc is 4 bit long, so avoiding overflow
...
...
@@ -94,7 +103,8 @@ void calculateTimings(uint32_t f, uint32_t fi2c, uint8_t *presc, uint8_t *sclh,
*
sclh
=
*
scll
=
(
f
/
(
fi2c
*
2
*
(
*
presc
+
1
))
-
1
)
-
(
7
/
(
*
presc
+
1
));
// SCLDEL >= (t_r + t_su) / ((PRESC+1)*t_i2c) - 1 ; approximated without
// subtracting 1
// subtracting 1. scldly and sdadly are calculated using values taken from
// the reference manual
uint32_t
scldly
=
0
,
sdadly
=
0
;
if
(
fi2c
==
100
)
{
...
...
@@ -115,7 +125,7 @@ void calculateTimings(uint32_t f, uint32_t fi2c, uint8_t *presc, uint8_t *sclh,
// max value of scldel is 15
*
scldel
=
((
scldly
<
16
)
?
(
scldly
-
1
)
:
15
);
// max value of sdadel is 15
m
// max value of sdadel is 15
*
sdadel
=
((
sdadly
<
16
)
?
(
sdadly
-
1
)
:
15
);
}
...
...
@@ -410,21 +420,24 @@ void I2CDriver::init()
uint32_t
f
=
ClockUtils
::
getAPBPeripheralsClock
(
ClockUtils
::
APB
::
APB1
)
/
1000
;
// Calculating for all the speed modes the clock parameters (so we won't
// have to calculate them again for every transaction)
// Standard mode (100 kHz)
calculateTimings
(
f
,
100
,
&
I2CConsts
::
PRESC_STD
,
&
I2CConsts
::
SCLH_STD
,
&
I2CConsts
::
SCLL_STD
,
&
I2CConsts
::
SCLDEL_STD
,
&
I2CConsts
::
SDADEL_STD
);
// Fast mode (400 kHz)
calculateTimings
(
f
,
400
,
&
I2CConsts
::
PRESC_F
,
&
I2CConsts
::
SCLH_F
,
&
I2CConsts
::
SCLL_F
,
&
I2CConsts
::
SCLDEL_F
,
&
I2CConsts
::
SDADEL_F
);
// Fast mode plus (1000 kHz)
calculateTimings
(
f
,
1000
,
&
I2CConsts
::
PRESC_FP
,
&
I2CConsts
::
SCLH_FP
,
&
I2CConsts
::
SCLL_FP
,
&
I2CConsts
::
SCLDEL_FP
,
&
I2CConsts
::
SDADEL_FP
);
// I2CCLK < (t_low - t_filters) / 4
// I2CCLK < t_high
// I2CCLK < 4/3 * t_SCL
// Enabling the peripheral after initialization
i2c
->
CR1
|=
I2C_CR1_PE
;
}
...
...
@@ -468,7 +481,7 @@ bool I2CDriver::write(const I2CSlaveConfig &slaveConfig, const void *buffer,
bool
I2CDriver
::
doOperation
(
const
I2CSlaveConfig
&
slaveConfig
)
{
//
Not ye
t supported
//
10-bit addressing no
t supported
D
(
assert
(
slaveConfig
.
addressing
==
Addressing
::
BIT7
&&
"Only 7-bit addressing supported!"
));
...
...
@@ -504,7 +517,8 @@ bool I2CDriver::doOperation(const I2CSlaveConfig &slaveConfig)
// Setting up transaction
setupTransaction
();
// Sending STOP condition and wake up thread
// Now proceeding as every other transaction (re-starting specific code
// already executed)
reStarting
=
false
;
// clearing pending flags
...
...
@@ -518,10 +532,14 @@ bool I2CDriver::doOperation(const I2CSlaveConfig &slaveConfig)
miosix
::
FastInterruptDisableLock
dLock
;
// Sending the start condition
// [WARNING]: In F7 the START condition is not generated immediately
// when set the flag, but the peripheral waits that the bus is free for
// sending the START condition + slave address. This could be bad since
// the peripheral isn't deterministic in time.
i2c
->
CR2
|=
I2C_CR2_START
;
//
s
etting automatic stop generation if we have to generate STOP
// condition. This
must
be done after the START condition generation
//
S
etting automatic stop generation if we have to generate STOP
// condition. This
MUST
be done after the START condition generation
// since, in case of a reStart, this would immediately end the previous
// transaction before the start condition is generated.
if
(
transaction
.
generateStop
)
...
...
@@ -543,13 +561,13 @@ bool I2CDriver::doOperation(const I2CSlaveConfig &slaveConfig)
void
I2CDriver
::
setupPeripheral
(
const
I2CSlaveConfig
&
slaveConfig
)
{
// Disabling the I2C peripheral before setting the registers
// Disabling the I2C peripheral before setting the registers.
// This will also perform a software reset, useful to restore the internal
// state machines and flags in order to start with a clear environment
i2c
->
CR1
&=
~
I2C_CR1_PE
;
// setting the SCLH and SCLL bits in I2C_TIMINGR register to generate
// correct timings for each speed modes.
// SDADEL and SCLDEL are set to 1 just to provide a bit of margin but not
// too much (in order not to slow down communication)
// Setting PRESC, SCLH, SCLL, SCLDEL and SDADEL bits in I2C_TIMINGR register
// to generate correct timings for each speed mode
if
(
slaveConfig
.
speed
==
Speed
::
STANDARD
)
{
i2c
->
TIMINGR
=
...
...
@@ -582,12 +600,13 @@ void I2CDriver::setupPeripheral(const I2CSlaveConfig &slaveConfig)
D
(
assert
(
false
&&
"speed not supported"
));
}
// setting addressing mode, read or write mode and slave address
// setting addressing mode and slave address (for 7-Bit addressing the 7
// bits have to be set on SADD[7:1])
i2c
->
CR2
=
(
slaveConfig
.
addressing
==
Addressing
::
BIT10
?
I2C_CR2_ADD10
:
0
)
|
(
slaveConfig
.
slaveAddress
<<
(
I2C_CR2_SADD_Pos
+
1
));
//
Finally
enabling the peripheral
//
Re-
enabling the peripheral
i2c
->
CR1
|=
I2C_CR1_PE
;
}
...
...
@@ -609,6 +628,9 @@ void I2CDriver::setupTransaction()
void
I2CDriver
::
setupReload
()
{
// If we are left with a communication of less than 256 bytes, we can do it
// without reloading, otherwise we must perform the transaction with the
// first 255 bytes and then perform a reload operation
if
((
transaction
.
nBytes
-
transaction
.
nBytesDone
)
<=
0xffu
)
{
i2c
->
CR2
=
...
...
@@ -626,7 +648,7 @@ void I2CDriver::setupReload()
void
I2CDriver
::
flushBus
()
{
// If there isn't any locked state return immediately
// If there isn't any locked state
or bus error
return immediately
if
(
!
((
lastError
&
(
Errors
::
BUS_LOCKED
|
Errors
::
BERR
))
&&
((
i2c
->
ISR
&
I2C_ISR_BUSY
))))
{
...
...
@@ -745,7 +767,7 @@ void I2CDriver::IRQhandleInterrupt()
if
(
i2c
->
ISR
&
I2C_ISR_NACKF
)
{
// "reserved" bit in the ISR register, so we don't collide with
// other fields
// other fields
. Set to force an error
error
=
1
<<
14
;
lastError
|=
Errors
::
AF
;
i2c
->
ICR
|=
I2C_ICR_NACKCF
;
...
...
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