prj to mdks
This commit is contained in:
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
|
||||
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
|
||||
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
|
||||
|
||||
The implementation is verified against the test vectors in:
|
||||
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
|
||||
|
||||
ECB-AES128
|
||||
----------
|
||||
|
||||
plain-text:
|
||||
6bc1bee22e409f96e93d7e117393172a
|
||||
ae2d8a571e03ac9c9eb76fac45af8e51
|
||||
30c81c46a35ce411e5fbc1191a0a52ef
|
||||
f69f2445df4f9b17ad2b417be66c3710
|
||||
|
||||
key:
|
||||
2b7e151628aed2a6abf7158809cf4f3c
|
||||
|
||||
resulting cipher
|
||||
3ad77bb40d7a3660a89ecaf32466ef97
|
||||
f5d3d58503b9699de785895a96fdbaaf
|
||||
43b1cd7f598ece23881b00e3ed030688
|
||||
7b0c785e27e8ad3f8223207104725dd4
|
||||
|
||||
|
||||
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||
You should pad the end of the string with zeros if this is not the case.
|
||||
For AES192/256 the key size is proportionally larger.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Includes: */
|
||||
/*****************************************************************************/
|
||||
#include <string.h> // CBC mode, for memset
|
||||
#include "aes.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Defines: */
|
||||
/*****************************************************************************/
|
||||
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||
#define Nb 4
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define Nk 8
|
||||
#define Nr 14
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define Nk 6
|
||||
#define Nr 12
|
||||
#else
|
||||
#define Nk 4 // The number of 32 bit words in a key.
|
||||
#define Nr 10 // The number of rounds in AES Cipher.
|
||||
#endif
|
||||
|
||||
// jcallan@github points out that declaring Multiply as a function
|
||||
// reduces code size considerably with the Keil ARM compiler.
|
||||
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
|
||||
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||
#define MULTIPLY_AS_A_FUNCTION 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Private variables: */
|
||||
/*****************************************************************************/
|
||||
// state - array holding the intermediate results during decryption.
|
||||
typedef uint8_t state_t[4][4];
|
||||
|
||||
|
||||
|
||||
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||
static const uint8_t sbox[256] = {
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
|
||||
|
||||
static const uint8_t rsbox[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
|
||||
|
||||
// The round constant word array, Rcon[i], contains the values given by
|
||||
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||
static const uint8_t Rcon[11] = {
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||
|
||||
/*
|
||||
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
|
||||
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||
*
|
||||
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||
*
|
||||
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Private functions: */
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
static uint8_t getSBoxValue(uint8_t num)
|
||||
{
|
||||
return sbox[num];
|
||||
}
|
||||
*/
|
||||
#define getSBoxValue(num) (sbox[(num)])
|
||||
/*
|
||||
static uint8_t getSBoxInvert(uint8_t num)
|
||||
{
|
||||
return rsbox[num];
|
||||
}
|
||||
*/
|
||||
#define getSBoxInvert(num) (rsbox[(num)])
|
||||
|
||||
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
uint8_t tempa[4]; // Used for the column/row operations
|
||||
|
||||
// The first round key is the key itself.
|
||||
for (i = 0; i < Nk; ++i)
|
||||
{
|
||||
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||
}
|
||||
|
||||
// All other round keys are found from the previous round keys.
|
||||
for (i = Nk; i < Nb * (Nr + 1); ++i)
|
||||
{
|
||||
{
|
||||
k = (i - 1) * 4;
|
||||
tempa[0]=RoundKey[k + 0];
|
||||
tempa[1]=RoundKey[k + 1];
|
||||
tempa[2]=RoundKey[k + 2];
|
||||
tempa[3]=RoundKey[k + 3];
|
||||
|
||||
}
|
||||
|
||||
if (i % Nk == 0)
|
||||
{
|
||||
// This function shifts the 4 bytes in a word to the left once.
|
||||
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||
|
||||
// Function RotWord()
|
||||
{
|
||||
const uint8_t u8tmp = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = u8tmp;
|
||||
}
|
||||
|
||||
// SubWord() is a function that takes a four-byte input word and
|
||||
// applies the S-box to each of the four bytes to produce an output word.
|
||||
|
||||
// Function Subword()
|
||||
{
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
|
||||
tempa[0] = tempa[0] ^ Rcon[i/Nk];
|
||||
}
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
if (i % Nk == 4)
|
||||
{
|
||||
// Function Subword()
|
||||
{
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
j = i * 4; k=(i - Nk) * 4;
|
||||
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||
}
|
||||
}
|
||||
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
}
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
|
||||
{
|
||||
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function adds the round key to state.
|
||||
// The round key is added to the state by an XOR function.
|
||||
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t i,j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
for (j = 0; j < 4; ++j)
|
||||
{
|
||||
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void SubBytes(state_t* state)
|
||||
{
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
for (j = 0; j < 4; ++j)
|
||||
{
|
||||
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The ShiftRows() function shifts the rows in the state to the left.
|
||||
// Each row is shifted with different offset.
|
||||
// Offset = Row number. So the first row is not shifted.
|
||||
static void ShiftRows(state_t* state)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to left
|
||||
temp = (*state)[0][1];
|
||||
(*state)[0][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[3][1];
|
||||
(*state)[3][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to left
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
// Rotate third row 3 columns to left
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[3][3];
|
||||
(*state)[3][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[1][3];
|
||||
(*state)[1][3] = temp;
|
||||
}
|
||||
|
||||
static uint8_t xtime(uint8_t x)
|
||||
{
|
||||
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
|
||||
}
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix
|
||||
static void MixColumns(state_t* state)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t Tmp, Tm, t;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
t = (*state)[i][0];
|
||||
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
|
||||
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
|
||||
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
|
||||
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
|
||||
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||
// The compiler seems to be able to vectorize the operation better this way.
|
||||
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||
#if MULTIPLY_AS_A_FUNCTION
|
||||
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||
{
|
||||
return (((y & 1) * x) ^
|
||||
((y>>1 & 1) * xtime(x)) ^
|
||||
((y>>2 & 1) * xtime(xtime(x))) ^
|
||||
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
|
||||
}
|
||||
#else
|
||||
#define Multiply(x, y) \
|
||||
( ((y & 1) * x) ^ \
|
||||
((y>>1 & 1) * xtime(x)) ^ \
|
||||
((y>>2 & 1) * xtime(xtime(x))) ^ \
|
||||
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
|
||||
|
||||
#endif
|
||||
|
||||
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
// MixColumns function mixes the columns of the state matrix.
|
||||
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||
// Please use the references to gain more information.
|
||||
static void InvMixColumns(state_t* state)
|
||||
{
|
||||
int i;
|
||||
uint8_t a, b, c, d;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
a = (*state)[i][0];
|
||||
b = (*state)[i][1];
|
||||
c = (*state)[i][2];
|
||||
d = (*state)[i][3];
|
||||
|
||||
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void InvSubBytes(state_t* state)
|
||||
{
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
for (j = 0; j < 4; ++j)
|
||||
{
|
||||
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InvShiftRows(state_t* state)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to right
|
||||
temp = (*state)[3][1];
|
||||
(*state)[3][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[0][1];
|
||||
(*state)[0][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to right
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
// Rotate third row 3 columns to right
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[1][3];
|
||||
(*state)[1][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[3][3];
|
||||
(*state)[3][3] = temp;
|
||||
}
|
||||
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
|
||||
// Cipher is the main function that encrypts the PlainText.
|
||||
static void Cipher(state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(0, state, RoundKey);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without MixColumns()
|
||||
for (round = 1; ; ++round)
|
||||
{
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
if (round == Nr) {
|
||||
break;
|
||||
}
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
}
|
||||
// Add round key to last round
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
}
|
||||
|
||||
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
static void InvCipher(state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr rounds are executed in the loop below.
|
||||
// Last one without InvMixColumn()
|
||||
for (round = (Nr - 1); ; --round)
|
||||
{
|
||||
InvShiftRows(state);
|
||||
InvSubBytes(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
if (round == 0) {
|
||||
break;
|
||||
}
|
||||
InvMixColumns(state);
|
||||
}
|
||||
|
||||
}
|
||||
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions: */
|
||||
/*****************************************************************************/
|
||||
#if defined(ECB) && (ECB == 1)
|
||||
|
||||
|
||||
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||
{
|
||||
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||
Cipher((state_t*)buf, ctx->RoundKey);
|
||||
}
|
||||
|
||||
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||
{
|
||||
// The next function call decrypts the PlainText with the Key using AES algorithm.
|
||||
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined(ECB) && (ECB == 1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
|
||||
{
|
||||
buf[i] ^= Iv[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uintptr_t i;
|
||||
uint8_t *Iv = ctx->Iv;
|
||||
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||
{
|
||||
XorWithIv(buf, Iv);
|
||||
Cipher((state_t*)buf, ctx->RoundKey);
|
||||
Iv = buf;
|
||||
buf += AES_BLOCKLEN;
|
||||
}
|
||||
/* store Iv in ctx for next call */
|
||||
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
|
||||
}
|
||||
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uintptr_t i;
|
||||
uint8_t storeNextIv[AES_BLOCKLEN];
|
||||
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||
{
|
||||
memcpy(storeNextIv, buf, AES_BLOCKLEN);
|
||||
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||
XorWithIv(buf, ctx->Iv);
|
||||
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
|
||||
buf += AES_BLOCKLEN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // #if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
|
||||
#if defined(CTR) && (CTR == 1)
|
||||
|
||||
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uint8_t buffer[AES_BLOCKLEN];
|
||||
|
||||
unsigned i;
|
||||
int bi;
|
||||
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
|
||||
{
|
||||
if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
|
||||
{
|
||||
|
||||
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||
Cipher((state_t*)buffer,ctx->RoundKey);
|
||||
|
||||
/* Increment Iv and handle overflow */
|
||||
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
|
||||
{
|
||||
/* inc will overflow */
|
||||
if (ctx->Iv[bi] == 255)
|
||||
{
|
||||
ctx->Iv[bi] = 0;
|
||||
continue;
|
||||
}
|
||||
ctx->Iv[bi] += 1;
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
|
||||
buf[i] = (buf[i] ^ buffer[bi]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if defined(CTR) && (CTR == 1)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,862 @@
|
||||
|
||||
#include "firmware.h"
|
||||
|
||||
|
||||
static uint8_t _fw_start_write_flag; /* 固件开始写入的标志位 */
|
||||
static uint16_t _update_progress; /* 固件更新的进度, 10000 制 */
|
||||
static uint16_t _update_progress_step_num; /* 固件更新进度的步进单位 */
|
||||
static uint16_t _storage_data_size; /* 固件包写入时记录暂存的固件分包大小,单位 byte */
|
||||
static uint32_t _write_part_addr; /* 固件包写入时记录写入 flash 的相对地址 */
|
||||
static uint16_t _write_last_pkg_size; /* 固件包写入时最后一个分包的大小,单位 byte */
|
||||
static uint8_t _fw_first_bytes[CONFIG_WRITE_BYTES_LEASET]; /* 固件包的前几个字节 */
|
||||
static uint8_t _upk_min_handle_buff[UPK_LEAST_HANDLE_BYTE]; /* upk 固件最小处理单位的缓存区,多次使用以降低系统资源开销 */
|
||||
static struct upk_head_t upkHdr; /* 用于存放 upk 固件包头 */
|
||||
|
||||
#if (CONFIG_DECRYPT)
|
||||
static struct AES_ctx aesCtx; /* AES 对象 */
|
||||
#endif
|
||||
|
||||
static struct BSP_FLASH _flash_app_part; /* APP 分区 */
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
static struct BSP_FLASH _flash_download_part; /* download 分区 */
|
||||
#if (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION)
|
||||
static struct BSP_FLASH _flash_factory_part; /* factory 分区 */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Extern function prototypes ------------------------------------------------*/
|
||||
extern void Firmware_OperateCallback(uint16_t progress);
|
||||
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static eErrCode _Write_FirmwareSubPackage( const struct BSP_FLASH *part,
|
||||
uint8_t *data,
|
||||
uint16_t pkg_size,
|
||||
uint8_t decrypt,
|
||||
FM_FIRMWARE_WRITE_DIR write_dir);
|
||||
|
||||
static void _Reset_Write(void);
|
||||
|
||||
|
||||
/* Exported functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief 初始化接口
|
||||
* @note
|
||||
* @retval None
|
||||
*/
|
||||
void FM_Init (void)
|
||||
{
|
||||
BSP_Flash_Init(&_flash_app_part, NAME_PART_APPLICATION, BASE_APPLICATION, SIZE_PART_APPLICATION);
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
BSP_Flash_Init(&_flash_download_part, NAME_PART_DOWNLOAD, BASE_DOWNLOAD, SIZE_PART_DOWNLOAD);
|
||||
#if (CONFIG_CHIP_PARTS > USE_DOUBLE_PARTITION)
|
||||
BSP_Flash_Init(&_flash_factory_part, NAME_PART_FACTORY, BASE_FACTORY, SIZE_PART_FACTORY);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf("onchip size : 0x%lX\r\n", SIZE_ONCHIP_FLASH);
|
||||
printf("0x%08lX+0x%lX 'parameters'.\r\n", BASE_PARAMETERS, SIZE_PART_PARAMETERS);
|
||||
printf("0x%08X+0x%X 'app'.\r\n", _flash_app_part.addr, _flash_app_part.len);
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
printf("0x%08X+0x%X 'download'.\r\n", _flash_download_part.addr, _flash_app_part.len);
|
||||
#if (CONFIG_CHIP_PARTS > USE_DOUBLE_PARTITION)
|
||||
printf("0x%08X+0x%X 'factory'.\r\n", _flash_factory_part.addr, _flash_app_part.len);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (CONFIG_DECRYPT)
|
||||
AES_init_ctx_iv(&aesCtx, (uint8_t *)AES256_KEY, (uint8_t *)AES256_IV);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 固件包是否有加密
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 0: 未加密。1: 有加密
|
||||
*/
|
||||
inline uint8_t FM_IsEncrypt(void)
|
||||
{
|
||||
/* 读取加密选项 */
|
||||
if (upkHdr.config[1] == 0x01)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 检测某个分区是否为空
|
||||
* @note ERR_OK: 分区数据空
|
||||
* @param[in] part_name: 分区名
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_IsEmpty(const char *part_name)
|
||||
{
|
||||
int read_len = 0;
|
||||
uint16_t i = 0;
|
||||
uint16_t need_read_size = UPK_LEAST_HANDLE_BYTE;
|
||||
uint32_t *p_data = (uint32_t *)_upk_min_handle_buff;
|
||||
uint32_t read_posit = 0;
|
||||
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL) {
|
||||
printf("%s: '%s' not found.\r\n", __func__, part_name);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
for (read_posit = 0; read_posit < part->len; ) {
|
||||
if ((part->len - read_posit) < UPK_LEAST_HANDLE_BYTE) {
|
||||
need_read_size = part->len - read_posit;
|
||||
}
|
||||
|
||||
read_len = BSP_Flash_Read(part, read_posit, _upk_min_handle_buff, need_read_size);
|
||||
if (read_len < 0) {
|
||||
printf("%s: read error (%d).\r\n", __func__, __LINE__);
|
||||
return ERR_READ_IS_EMPTY_ERR;
|
||||
}
|
||||
|
||||
for (i = 0; i < (UPK_LEAST_HANDLE_BYTE / sizeof(p_data)); i++) {
|
||||
if (p_data[i] != 0xFFFFFFFF) {
|
||||
printf("part '%s' not empty.\r\n", part_name);
|
||||
return ERR_FLASH_NO_EMPTY;
|
||||
}
|
||||
}
|
||||
read_posit += read_len;
|
||||
}
|
||||
|
||||
//printf("%s: '%s' part empty.\r\n", __func__, part_name);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取固件包的固件版本
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 固件新版本
|
||||
*/
|
||||
inline char * FM_GetNewFirmwareVersion(void)
|
||||
{
|
||||
return upkHdr.fw_new_ver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取源固件的 CRC32 值
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 源固件的 CRC32 值
|
||||
*/
|
||||
inline uint32_t FM_GetRawCRC32(void)
|
||||
{
|
||||
return upkHdr.raw_crc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 暂存固件包头
|
||||
* @note 会同时校验固件包头
|
||||
* @param[in] part_name: 分区名
|
||||
* @param[in] data: 数据
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_StorageFirmwareHead(const char *part_name, uint8_t *data)
|
||||
{
|
||||
uint32_t head_crc = 0xFFFFFFFF;
|
||||
uint8_t *pHdr = (uint8_t *)&upkHdr;
|
||||
|
||||
ASSERT(part_name != NULL);
|
||||
ASSERT(data != NULL);
|
||||
|
||||
_Reset_Write();
|
||||
memcpy(pHdr, data, UPK_HEAD_SIZE);
|
||||
|
||||
#if (!CONFIG_DECRYPT)
|
||||
/* 若固件包加密,检查是否有解密组件 */
|
||||
if (FM_IsEncrypt()) {
|
||||
printf("%s: no decrypt component\r\n", __func__);
|
||||
return ERR_NO_DECRYPT_COMPONENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL) {
|
||||
printf("%s: not found.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
//printf("%s: '%s' part.\r\n", __func__, part_name);
|
||||
|
||||
if (strncmp(upkHdr.name, "upk", sizeof("upk")) != 0) {
|
||||
return ERR_FAULT_FIRMWARE;
|
||||
}
|
||||
|
||||
if ((upkHdr.pkg_size > part->len)
|
||||
|| (upkHdr.raw_size > part->len)) {
|
||||
return ERR_FIRMWARE_OVERSIZE;
|
||||
}
|
||||
|
||||
head_crc = crc32_step(head_crc, pHdr, UPK_HEAD_SIZE - 4);
|
||||
if (head_crc != upkHdr.head_crc) {
|
||||
printf("%s: head crc verify failed. (%.8X - %.8X)\r\n", __func__, upkHdr.head_crc, head_crc);
|
||||
return ERR_FIRMWARE_HEAD_VERIFY_ERR;
|
||||
}
|
||||
|
||||
printf("\n\r--------------------\n\r");
|
||||
printf("head: \t\t%s\n\r", upkHdr.name);
|
||||
printf("config: \t%d %d %d %d\n\r", upkHdr.config[0], upkHdr.config[1], upkHdr.config[2], upkHdr.config[3]);
|
||||
printf("old_ver: \t%d.%d.%d.%d\n\r", upkHdr.fw_old_ver[0], upkHdr.fw_old_ver[1], upkHdr.fw_old_ver[2], upkHdr.fw_old_ver[3]);
|
||||
printf("new_ver: \t%d.%d.%d.%d\n\r", upkHdr.fw_new_ver[0], upkHdr.fw_new_ver[1], upkHdr.fw_new_ver[2], upkHdr.fw_new_ver[3]);
|
||||
printf("string: \t%s\n\r",upkHdr.user_string);
|
||||
printf("partition: \t%s\n\r", upkHdr.part_name);
|
||||
printf("raw_size: \t%d\n\r", upkHdr.raw_size);
|
||||
printf("pkg_size: \t%d\n\r", upkHdr.pkg_size);
|
||||
printf("timestamp: \t%d\n\r", upkHdr.timestamp);
|
||||
printf("raw_crc: \t%.8X\n\r", upkHdr.raw_crc);
|
||||
printf("pkg_crc: \t%.8X\n\r", upkHdr.pkg_crc);
|
||||
printf("head_crc: \t%.8X\n\r", upkHdr.head_crc);
|
||||
printf("--------------------\n\r");
|
||||
|
||||
/* 计算固件更新进度的最小单位,降低过程计算量,无更新进度需求可删除 */
|
||||
_update_progress_step_num = upkHdr.pkg_size / UPK_LEAST_HANDLE_BYTE;
|
||||
_update_progress_step_num += upkHdr.pkg_size % UPK_LEAST_HANDLE_BYTE;
|
||||
_update_progress_step_num = 10000 / _update_progress_step_num;
|
||||
//printf("%s: progress unit: %d\r\n", __func__, _update_progress_step_num);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 校验已放置在分区的固件包的包体数据的正确性
|
||||
* @note 一般要先校验包头,注意各分区包体的偏移地址有区别
|
||||
* @param[in] part_name: 分区名称
|
||||
* @param[in] crc32: 需进行比对的 CRC32 校验值
|
||||
* @param[in] is_auto_fill: 是否自动填充固件的首地址数据
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_VerifyFirmware (const char *part_name, uint32_t crc32, uint8_t is_auto_fill)
|
||||
{
|
||||
int read_len = 0;
|
||||
uint8_t app_part_flag = 0;
|
||||
uint32_t pkg_size = 0;
|
||||
uint32_t body_crc = 0xFFFFFFFF;
|
||||
uint32_t read_posit = 0;
|
||||
uint32_t read_posit_temp = 0;
|
||||
uint16_t need_read_size = UPK_LEAST_HANDLE_BYTE;
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
uint8_t first_flag = 0;
|
||||
#endif
|
||||
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
#if (!CONFIG_DECRYPT)
|
||||
/* 若固件包加密,检查是否有解密组件 */
|
||||
if (FM_IsEncrypt()) {
|
||||
printf("%s: no decrypt component\r\n", __func__);
|
||||
return ERR_NO_DECRYPT_COMPONENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strncmp(part_name, NAME_PART_APPLICATION, MAX_NAME_LEN) == 0) {
|
||||
app_part_flag = 1;
|
||||
}
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL) {
|
||||
printf("%s: not found.\r\n", part_name);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
hex_printf((uint8_t *)&upkHdr, UPK_HEAD_SIZE);
|
||||
|
||||
printf("--------------------\n\r");
|
||||
printf("head: \t\t%s\n\r", upkHdr.name);
|
||||
printf("config: \t%d %d %d %d\n\r", upkHdr.config[0], upkHdr.config[1], upkHdr.config[2], upkHdr.config[3]);
|
||||
printf("old_ver: \t%d.%d.%d.%d\n\r", upkHdr.fw_old_ver[0], upkHdr.fw_old_ver[1], upkHdr.fw_old_ver[2], upkHdr.fw_old_ver[3]);
|
||||
printf("new_ver: \t%d.%d.%d.%d\n\r", upkHdr.fw_new_ver[0], upkHdr.fw_new_ver[1], upkHdr.fw_new_ver[2], upkHdr.fw_new_ver[3]);
|
||||
printf("string: \t%s\n\r",upkHdr.user_string);
|
||||
printf("partition: \t%s\n\r", upkHdr.part_name);
|
||||
printf("raw_size: \t%d\n\r", upkHdr.raw_size);
|
||||
printf("pkg_size: \t%d\n\r", upkHdr.pkg_size);
|
||||
printf("timestamp: \t%d\n\r", upkHdr.timestamp);
|
||||
printf("raw_crc: \t%.8X\n\r", upkHdr.raw_crc);
|
||||
printf("pkg_crc: \t%.8X\n\r", upkHdr.pkg_crc);
|
||||
printf("head_crc: \t%.8X\n\r", upkHdr.head_crc);
|
||||
printf("--------------------\n\r");
|
||||
|
||||
if (app_part_flag) {
|
||||
pkg_size = upkHdr.raw_size;
|
||||
} else {
|
||||
pkg_size = upkHdr.pkg_size;
|
||||
}
|
||||
|
||||
/* 校验固件包体的数据正确性 */
|
||||
for (; read_posit < pkg_size; ) {
|
||||
/* 剩余的数据数小于最小处理单位时,按剩余字节数处理 */
|
||||
if ((pkg_size - read_posit) < UPK_LEAST_HANDLE_BYTE) {
|
||||
need_read_size = pkg_size - read_posit;
|
||||
}
|
||||
|
||||
/* 非 APP 分区,需要偏移包头的地址才是包体 */
|
||||
if (app_part_flag) {
|
||||
read_posit_temp = read_posit;
|
||||
} else {
|
||||
read_posit_temp = read_posit + UPK_HEAD_SIZE;
|
||||
}
|
||||
|
||||
read_len = BSP_Flash_Read(part, read_posit_temp, _upk_min_handle_buff, need_read_size);
|
||||
if (read_len < 0) {
|
||||
printf("%s: read error (%d).\r\n", __func__, __LINE__);
|
||||
return ERR_VERIFY_READ_ERR;
|
||||
}
|
||||
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
if (is_auto_fill) {
|
||||
if (first_flag == 0) {
|
||||
first_flag = 1;
|
||||
for (uint8_t i = 0; i < CONFIG_WRITE_BYTES_LEASET; i++) {
|
||||
_upk_min_handle_buff[i] = _fw_first_bytes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
body_crc = crc32_step(body_crc, _upk_min_handle_buff, read_len);
|
||||
read_posit += read_len;
|
||||
}
|
||||
|
||||
if (body_crc != crc32) {
|
||||
printf("%s: '%s' body crc verify failed. (%08X vs %08X)\r\n", __func__, part_name, crc32, body_crc);
|
||||
if (app_part_flag) {
|
||||
return ERR_RAW_BODY_VERIFY_ERR;
|
||||
} else {
|
||||
return ERR_PKG_BODY_VERIFY_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 擦除某个分区的固件
|
||||
* @note
|
||||
* @param[in] part_name: 分区名称
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_EraseFirmware(const char *part_name)
|
||||
{
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL)
|
||||
{
|
||||
printf("%s: not found %s part.\r\n", __func__, part_name);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Erase(part, 0, part->len) < 0)
|
||||
{
|
||||
printf("%s: %s part erase failed.\r\n", __func__, part_name);
|
||||
return ERR_ERASE_PART_ERR;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 固件写入分区的最终阶段,将分区首地址的几个字节数据写入 flash
|
||||
* @note 程序调用 _Write_FirmwareSubPackage 函数时已暂存进 _fw_first_bytes
|
||||
* @param[in] part_name: 分区名称
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_WriteFirmwareDone (const char *part_name)
|
||||
{
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL) {
|
||||
printf("%s: not found part.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Write(part, 0, _fw_first_bytes, CONFIG_WRITE_BYTES_LEASET) < 0) {
|
||||
printf("%s: write error (%d).\r\n", __func__, __LINE__);
|
||||
return ERR_WRITE_FIRST_ADDR_ERR;
|
||||
}
|
||||
|
||||
_Reset_Write();
|
||||
Firmware_OperateCallback(10000);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将固件分包按顺序写入分区
|
||||
* @note 由于固件包头已经写入,这里写入的是固件包体,需要注意在 flash 的偏移位置
|
||||
* @param[in] part_name: 分区名称
|
||||
* @param[in] data: 数据包
|
||||
* @param[in] pkg_size: 数据包大小,单位 byte
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_WriteFirmwareSubPackage(const char *part_name, uint8_t *data, uint16_t pkg_size)
|
||||
{
|
||||
ASSERT(part_name != NULL);
|
||||
ASSERT(data != NULL);
|
||||
ASSERT(pkg_size != 0);
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL)
|
||||
{
|
||||
printf("%s: not found %s part.\r\n", __func__, part_name);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
printf(",");
|
||||
|
||||
#if (CONFIG_CHIP_PARTS == USE_SINGLE_PARTITION)
|
||||
uint8_t decrypt = 0;
|
||||
|
||||
/* 读取加密选项 */
|
||||
decrypt = FM_IsEncrypt();
|
||||
|
||||
return _Write_FirmwareSubPackage(part, data, pkg_size, decrypt, FM_DIR_HOST_TO_APP); /* 写入前解密 */
|
||||
#else
|
||||
return _Write_FirmwareSubPackage(part, data, pkg_size, 0, FM_DIR_HOST_TO_DOWNLOAD); /* 写入前不解密 */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 检查固件的完整性
|
||||
* @note 通过首地址数据最后写入的机制,判断首地址 4 个字节是否有正确的数据
|
||||
* @param[in] addr: 分区首地址
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_CheckFirmwareIntegrity(uint32_t addr)
|
||||
{
|
||||
uint32_t value = *(volatile uint32_t *)addr;
|
||||
eErrCode fw_integrity = ERR_JUMP_TO_APP_ERR;
|
||||
|
||||
printf("\r\nvalue = 0x%08X @ offset 0x%.8X", value, addr);
|
||||
|
||||
if (BASE_APPLICATION == addr) {
|
||||
fw_integrity = ((value & 0x2FF00000) == 0x20000000) ? ERR_OK : ERR_JUMP_TO_APP_ERR;
|
||||
}
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
else if ((BASE_DOWNLOAD == addr)||(BASE_FACTORY == addr)) {
|
||||
if (UPK_IDENTIFIER == value) {
|
||||
fw_integrity = ERR_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return fw_integrity;
|
||||
}
|
||||
|
||||
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
/**
|
||||
* @brief 判断是否要进行固件自动更新
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 0: 无须更新。1: 需自动更新
|
||||
*/
|
||||
uint8_t FM_IsNeedAutoUpdate(void)
|
||||
{
|
||||
#if (CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP)
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(NAME_PART_APPLICATION);
|
||||
if (part == NULL) {
|
||||
printf("%s: not found app part.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Read(part, (SIZE_PART_APPLICATION - UPK_VERSION_SIZE), (uint8_t *)&upkHdr.fw_old_ver[0], UPK_VERSION_SIZE) < 0)
|
||||
{
|
||||
printf("%s: read error.\r\n", __func__);
|
||||
return ERR_READ_VER_ERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("fw old ver: V%d.%d.%d.%d\r\n", upkHdr.fw_old_ver[0], upkHdr.fw_old_ver[1], upkHdr.fw_old_ver[2], upkHdr.fw_old_ver[3]);
|
||||
printf("fw new ver: V%d.%d.%d.%d\r\n", upkHdr.fw_new_ver[0], upkHdr.fw_new_ver[1], upkHdr.fw_new_ver[2], upkHdr.fw_new_ver[3]);
|
||||
|
||||
if (upkHdr.fw_old_ver[0] != upkHdr.fw_new_ver[0]
|
||||
|| upkHdr.fw_old_ver[1] != upkHdr.fw_new_ver[1]
|
||||
|| upkHdr.fw_old_ver[2] != upkHdr.fw_new_ver[2]
|
||||
|| upkHdr.fw_old_ver[3] != upkHdr.fw_new_ver[3]) {
|
||||
printf("Need to update.\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取当前操作的固件包的分区名称
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 分区名称
|
||||
*/
|
||||
inline char * FM_GetPartName(void)
|
||||
{
|
||||
return upkHdr.part_name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取旧的固件版本,即 APP 分区正在运行的固件版本
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 固件旧版本
|
||||
*/
|
||||
inline char * FM_GetOldFirmwareVersion(void)
|
||||
{
|
||||
return upkHdr.fw_old_ver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取打包后固件的 CRC32 值
|
||||
* @note 调用前需确保 upkHdr 已经读入了数据
|
||||
* @retval 打包后固件的CRC32值
|
||||
*/
|
||||
inline uint32_t FM_GetPackageCRC32(void)
|
||||
{
|
||||
return upkHdr.pkg_crc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将分区内的固件包头读出
|
||||
* @note 读出后的数据将放在 upkHdr 中
|
||||
* @param[in] part_name: 分区名称
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_ReadFirmwareHead(const char *part_name)
|
||||
{
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
_Reset_Write();
|
||||
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL)
|
||||
{
|
||||
printf("%s: not found.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Read(part, 0, (uint8_t *)&upkHdr, UPK_HEAD_SIZE) < 0)
|
||||
{
|
||||
printf("%s: read error.\r\n", __func__);
|
||||
return ERR_READ_FIRMWARE_HEAD_ERR;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 从某个分区将固件包更新至 APP 分区
|
||||
* @note 读取 -> 解密 -> 写入
|
||||
* @param[in] from_part_name: 放置需要更新至 APP 分区的固件包的分区
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_UpdateToAPP(const char *from_part_name)
|
||||
{
|
||||
int read_len = 0;
|
||||
uint8_t decrypt = 0;
|
||||
uint32_t read_posit = 0;
|
||||
uint32_t write_posit = 0;
|
||||
uint32_t need_read_size = UPK_LEAST_HANDLE_BYTE;
|
||||
eErrCode result = ERR_OK;
|
||||
|
||||
ASSERT(from_part_name != NULL);
|
||||
|
||||
const struct BSP_FLASH *app_part = NULL;
|
||||
const struct BSP_FLASH *firmware_part = NULL;
|
||||
|
||||
app_part = BSP_Flash_GetHandle(NAME_PART_APPLICATION);
|
||||
if (app_part == NULL) {
|
||||
printf("%s: not found.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
firmware_part = BSP_Flash_GetHandle(from_part_name);
|
||||
if (firmware_part == NULL) {
|
||||
printf("%s: not found %s part.\r\n", __func__, from_part_name);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
_Reset_Write();
|
||||
printf("part '%s' write to 'app'.\r\n", from_part_name);
|
||||
|
||||
/* 读取加密选项 */
|
||||
decrypt = FM_IsEncrypt();
|
||||
|
||||
for (write_posit = 0; write_posit < upkHdr.pkg_size; ) {
|
||||
if ((upkHdr.pkg_size - read_posit) < UPK_LEAST_HANDLE_BYTE) {
|
||||
need_read_size = upkHdr.pkg_size - read_posit;
|
||||
}
|
||||
|
||||
read_len = BSP_Flash_Read(firmware_part, (read_posit + UPK_HEAD_SIZE), _upk_min_handle_buff, need_read_size);
|
||||
if (read_len < 0) {
|
||||
printf("%s: read error (%d).\r\n", __func__, __LINE__);
|
||||
return ERR_UPDATE_READ_ERR;
|
||||
}
|
||||
|
||||
result = _Write_FirmwareSubPackage(app_part, _upk_min_handle_buff, read_len, decrypt, FM_DIR_DOWNLOAD_TO_APP);
|
||||
if (result) {
|
||||
printf("%s: write error (%d).\r\n", __func__, __LINE__);
|
||||
return result;
|
||||
}
|
||||
|
||||
read_posit += read_len;
|
||||
write_posit += read_len;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
#if (CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD)
|
||||
/**
|
||||
* @brief 更新固件包中的版本信息
|
||||
* @note
|
||||
* @param[in] part_name: 分区名称
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_UpdateFirmwareVersion(const char *part_name)
|
||||
{
|
||||
ASSERT(part_name != NULL);
|
||||
|
||||
#if (ONCHIP_FLASH_ERASE_GRANULARITY > UPK_LEAST_HANDLE_BYTE)
|
||||
#error "erase granularity oversize than _upk_min_handle_buff array"
|
||||
#endif
|
||||
/* 将 download 分区首地址的数据读出,长度为片内 flash 最小擦除粒度 */
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(part_name);
|
||||
if (part == NULL)
|
||||
{
|
||||
printf("%s: not found.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
printf("%s: part name: %s\r\n", __func__, part_name);
|
||||
|
||||
if (BSP_Flash_Read(part, 0, &_upk_min_handle_buff[0], ONCHIP_FLASH_ERASE_GRANULARITY) < 0)
|
||||
{
|
||||
printf("%s: read error.\r\n", __func__);
|
||||
return ERR_UPDATE_VER_READ_ERR;
|
||||
}
|
||||
|
||||
/* 修改固件包头中旧版本字段的版本信息为新的固件版本 */
|
||||
struct upk_head_t *p_pkg_head = (struct upk_head_t *)&_upk_min_handle_buff[0];
|
||||
|
||||
p_pkg_head->fw_old_ver[0] = p_pkg_head->fw_new_ver[0];
|
||||
p_pkg_head->fw_old_ver[1] = p_pkg_head->fw_new_ver[1];
|
||||
p_pkg_head->fw_old_ver[2] = p_pkg_head->fw_new_ver[2];
|
||||
p_pkg_head->fw_old_ver[3] = p_pkg_head->fw_new_ver[3];
|
||||
|
||||
/* 将读出数据的区域擦除 */
|
||||
if (BSP_Flash_Erase(part, 0, ONCHIP_FLASH_ERASE_GRANULARITY) < 0)
|
||||
{
|
||||
printf("%s: %s part erase failed.\r\n", __func__, part_name);
|
||||
return ERR_UPDATE_VER_ERASE_ERR;
|
||||
}
|
||||
|
||||
/* 将新的数据写入擦除的区域 */
|
||||
if (BSP_Flash_Write(part, 0, &_upk_min_handle_buff[0], ONCHIP_FLASH_ERASE_GRANULARITY) < 0)
|
||||
{
|
||||
printf("%s: write error (%d).\r\n", __func__, __LINE__);
|
||||
return ERR_UPDATE_VER_WRITE_ERR;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *)&upkHdr, &_upk_min_handle_buff[0], UPK_HEAD_SIZE);
|
||||
printf("fw old ver: V%d.%d.%d.%d\r\n", p_pkg_head->fw_old_ver[0], p_pkg_head->fw_old_ver[1], p_pkg_head->fw_old_ver[2], p_pkg_head->fw_old_ver[3]);
|
||||
printf("fw new ver: V%d.%d.%d.%d\r\n", p_pkg_head->fw_new_ver[0], p_pkg_head->fw_new_ver[1], p_pkg_head->fw_new_ver[2], p_pkg_head->fw_new_ver[3]);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
#elif (CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP)
|
||||
/**
|
||||
* @brief 更新固件包中的版本信息
|
||||
* @note
|
||||
* @param[in] part_name: 分区名称
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode FM_UpdateFirmwareVersion(const char *part_name)
|
||||
{
|
||||
const struct BSP_FLASH *part = NULL;
|
||||
|
||||
part = BSP_Flash_GetHandle(NAME_PART_APPLICATION);
|
||||
if (part == NULL)
|
||||
{
|
||||
printf("%s: not found APP part.\r\n", __func__);
|
||||
return ERR_NO_THIS_PART;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Read(part, (SIZE_PART_APPLICATION - UPK_VERSION_SIZE), (uint8_t *)&upkHdr.fw_old_ver[0], UPK_VERSION_SIZE) < 0)
|
||||
{
|
||||
printf("%s: read error.\r\n", __func__);
|
||||
return ERR_READ_VER_ERR;
|
||||
}
|
||||
|
||||
if (upkHdr.fw_old_ver[0] != 0xFF
|
||||
|| upkHdr.fw_old_ver[1] != 0xFF
|
||||
|| upkHdr.fw_old_ver[2] != 0xFF
|
||||
|| upkHdr.fw_old_ver[3] != 0xFF)
|
||||
{
|
||||
printf("%s: version area no erase.\r\n", __func__);
|
||||
return ERR_VER_AREA_NO_ERASE;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Write(part, (SIZE_PART_APPLICATION - UPK_VERSION_SIZE), (uint8_t *)&upkHdr.fw_new_ver[0], UPK_VERSION_SIZE) < 0)
|
||||
{
|
||||
printf("%s: write error.\r\n", __func__);
|
||||
return ERR_WRITE_VER_ERR;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#endif /* #if (CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD) */
|
||||
|
||||
#endif /* #if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION) */
|
||||
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief 复位写固件的一些记录信息
|
||||
* @note
|
||||
* @retval None
|
||||
*/
|
||||
static void _Reset_Write(void)
|
||||
{
|
||||
_fw_start_write_flag = 0; /* 固件开始写入的标志位 */
|
||||
_update_progress = 0; /* 固件更新的进度, 10000 制 */
|
||||
_storage_data_size = 0; /* 固件包写入时记录暂存的固件分包大小,单位 byte */
|
||||
_write_part_addr = 0; /* 固件包写入时记录写入 flash 的相对地址 */
|
||||
_write_last_pkg_size = 0; /* 固件包写入时最后一个分包的大小,单位 byte */
|
||||
}
|
||||
|
||||
uint32_t wcrc32 = 0xFFFFFFFF;
|
||||
uint32_t wlen = 0;
|
||||
/**
|
||||
* @brief 将固件分包按顺序写入某个分区
|
||||
* @note 循环调用本函数,无须指定写入地址,函数内部自行记录已写入的大小
|
||||
* @param[in] part: 分区对象
|
||||
* @param[in] data: 数据
|
||||
* @param[in] pkg_size: 数据大小,单位 byte
|
||||
* @param[in] decrypt: 0: 固件包无加密。1: 固件包有加密
|
||||
* @retval eErrCode
|
||||
*/
|
||||
static eErrCode _Write_FirmwareSubPackage( const struct BSP_FLASH *part,
|
||||
uint8_t *data,
|
||||
uint16_t pkg_size,
|
||||
uint8_t decrypt,
|
||||
FM_FIRMWARE_WRITE_DIR write_dir)
|
||||
{
|
||||
uint8_t *fw_4096byte_buff = data;
|
||||
|
||||
/* 主机直接下发的固件分包不满 UPK_LEAST_HANDLE_BYTE 个字节,需要先暂存至满足后再写入 */
|
||||
if (write_dir == FM_DIR_HOST_TO_APP) {
|
||||
fw_4096byte_buff = &_upk_min_handle_buff[0];
|
||||
|
||||
/* 判断是否是最后一个包 */
|
||||
if (_storage_data_size == 0) {
|
||||
if (upkHdr.pkg_size - _write_part_addr < UPK_LEAST_HANDLE_BYTE)
|
||||
{
|
||||
/* 最后一个固件分包的标志 */
|
||||
_write_last_pkg_size = upkHdr.pkg_size - _write_part_addr;
|
||||
printf("_write_last_pkg_size : %d\r\n", _write_last_pkg_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* 小于最小处理单位时,暂存 */
|
||||
if (_storage_data_size < UPK_LEAST_HANDLE_BYTE) {
|
||||
memcpy(&fw_4096byte_buff[_storage_data_size], data, pkg_size);
|
||||
_storage_data_size += pkg_size;
|
||||
|
||||
if (_write_last_pkg_size) {
|
||||
if (_storage_data_size < _write_last_pkg_size) {
|
||||
return ERR_OK;
|
||||
}
|
||||
} else if (_storage_data_size < UPK_LEAST_HANDLE_BYTE) {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 从 download 或 factory 更新至 APP ,因可以直接读取 UPK_LEAST_HANDLE_BYTE 个字节,所以无须暂存 */
|
||||
else {
|
||||
if (_fw_start_write_flag == 0) {
|
||||
wlen = upkHdr.pkg_size;
|
||||
_storage_data_size = pkg_size;
|
||||
} else {
|
||||
if (wlen >= pkg_size) {
|
||||
wlen -= pkg_size;
|
||||
_storage_data_size = pkg_size;
|
||||
} else {
|
||||
_storage_data_size = wlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (CONFIG_DECRYPT)
|
||||
if (decrypt) {
|
||||
AES_CBC_decrypt_buffer(&aesCtx, fw_4096byte_buff, _storage_data_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 保存首地址的几个字节数据,等待最后写入 */
|
||||
if (_fw_start_write_flag == 0) {
|
||||
for (uint8_t i = 0; i < CONFIG_WRITE_BYTES_LEASET; i++) {
|
||||
_fw_first_bytes[i] = fw_4096byte_buff[i];
|
||||
}
|
||||
|
||||
fw_4096byte_buff += CONFIG_WRITE_BYTES_LEASET;
|
||||
_storage_data_size -= CONFIG_WRITE_BYTES_LEASET;
|
||||
_write_part_addr = CONFIG_WRITE_BYTES_LEASET;
|
||||
}
|
||||
|
||||
if (BSP_Flash_Write(part, _write_part_addr, fw_4096byte_buff, _storage_data_size) < 0) {
|
||||
printf("%s: write error (%d) 0x%08X + 0x%08X, len %d.\r\n", __func__, __LINE__,
|
||||
part->addr,_write_part_addr, _storage_data_size);
|
||||
_Reset_Write();
|
||||
return ERR_WRITE_PART_ERR;
|
||||
}
|
||||
|
||||
if (_storage_data_size!=92) {
|
||||
wcrc32 = crc32_step(wcrc32, fw_4096byte_buff, _storage_data_size);
|
||||
}
|
||||
|
||||
_write_part_addr += _storage_data_size;
|
||||
_storage_data_size = 0;
|
||||
_fw_start_write_flag = 1;
|
||||
|
||||
_update_progress += _update_progress_step_num;
|
||||
Firmware_OperateCallback(_update_progress);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 此文件用于关闭 semihosting
|
||||
*/
|
||||
#include "common.h"
|
||||
|
||||
/* 告诉编译器若没有使用 MicroLIB ,则 main() 函数不需要入口参数 */
|
||||
#if __IS_COMPILER_ARM_COMPILER_6__
|
||||
#ifndef __MICROLIB
|
||||
__asm(".global __ARM_use_no_argv\n\t");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 关闭 semihosting */
|
||||
#if __IS_COMPILER_ARM_COMPILER_6__
|
||||
__asm(".global __use_no_semihosting");
|
||||
|
||||
/* AC6 会因为关闭 semihosting 缺这个函数,所以要补上 */
|
||||
void _sys_exit(int ret)
|
||||
{
|
||||
(void)ret;
|
||||
while(1) {}
|
||||
}
|
||||
#elif __IS_COMPILER_ARM_COMPILER_5__
|
||||
#pragma import(__use_no_semihosting)
|
||||
#endif
|
||||
|
||||
/* AC5 和 AC6 都会因为关闭 semihosting 缺这个函数,所以要补上 */
|
||||
#if __IS_COMPILER_ARM_COMPILER__
|
||||
void _ttywrch(int ch)
|
||||
{
|
||||
(void)ch;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 当使用 AC6 开启 MicroLIB 时,若有使用 assert() 的需求,需要自己实现 __aeabi_assert() */
|
||||
#if __IS_COMPILER_ARM_COMPILER_6__ && defined(__MICROLIB)
|
||||
void __aeabi_assert(const char *chCond, const char *chLine, int wErrCode)
|
||||
{
|
||||
(void)chCond;
|
||||
(void)chLine;
|
||||
(void)wErrCode;
|
||||
|
||||
while(1) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "transfer.h"
|
||||
|
||||
|
||||
#if (DT_ENABLE_BROKEN_FRAME_DETECT)
|
||||
static uint8_t timeo_frame = 0;
|
||||
static struct drv_timer_t timerFrameBroken;
|
||||
|
||||
static void timerFrameBrokenCallback (void *user_data)
|
||||
{
|
||||
timeo_frame = 1;
|
||||
//printf("frame detect clock time up!\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t DT_Port_IsRecvData (struct transfer_t *xfer)
|
||||
{
|
||||
#if (DT_ENABLE_BROKEN_FRAME_DETECT)
|
||||
if (timeo_frame) {
|
||||
timeo_frame = 0;
|
||||
|
||||
return BSP_UART_ERR_OK;
|
||||
} else if (BSP_UART_IsFrameEnd((BSP_UART_ID)xfer->if_id) == BSP_UART_ERR_OK) {
|
||||
drv_timer_linkUserData(&timerFrameBroken, xfer);
|
||||
drv_timer_restart(&timerFrameBroken);
|
||||
return BSP_UART_ERR_NO_RECV_FRAME;
|
||||
}
|
||||
|
||||
return BSP_UART_ERR_NO_RECV_FRAME;
|
||||
#else
|
||||
|
||||
return BSP_UART_IsFrameEnd((BSP_UART_ID)xfer->if_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DT_Send (struct transfer_t *xfer, uint8_t *data, uint32_t len)
|
||||
{
|
||||
BSP_UART_Send((BSP_UART_ID)xfer->if_id, data, len, 0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 检测是否接收到一帧数据的轮询接口
|
||||
* @note
|
||||
* @param[in] xfer: 传输控制块对象
|
||||
* @retval exRESULT
|
||||
*/
|
||||
exRESULT DT_PollingReceive (struct transfer_t *xfer)
|
||||
{
|
||||
exRESULT state = X_RESULT_NO_DATA;
|
||||
|
||||
if (DT_Port_IsRecvData(xfer) == 0) {
|
||||
state = X_RESULT_RECV_FRAME;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 数据传输层初始化
|
||||
* @note
|
||||
* @param[in] xfer: 传输控制块对象
|
||||
* @param[in] if_id: 传输接口 ID
|
||||
* @param[in] buff: 用于接收数据的缓冲池,单位 byte
|
||||
* @param[in] len: 指示接收到的数据长度,单位 byte
|
||||
* @param[in] buff_size: 数据池最大容量,单位 byte
|
||||
* @retval None
|
||||
*/
|
||||
void DT_Init (struct transfer_t *xfer, uint8_t if_id, uint8_t *buff, uint16_t *len, uint32_t buff_size)
|
||||
{
|
||||
ASSERT(xfer != NULL);
|
||||
|
||||
xfer->if_id = if_id;
|
||||
xfer->rx_buff = buff;
|
||||
xfer->rx_len = len;
|
||||
xfer->rx_buff_size = buff_size;
|
||||
|
||||
|
||||
BSP_UART_Init((BSP_UART_ID)xfer->if_id);
|
||||
BSP_UART_LinkUserData((BSP_UART_ID)xfer->if_id, xfer);
|
||||
BSP_UART_EnableReceive( (BSP_UART_ID)xfer->if_id,
|
||||
xfer->rx_buff,
|
||||
xfer->rx_len,
|
||||
xfer->rx_buff_size);
|
||||
|
||||
#if (DT_ENABLE_BROKEN_FRAME_DETECT)
|
||||
drv_timer_init(&timerFrameBroken,
|
||||
timerFrameBrokenCallback,
|
||||
BROKEN_FRAME_INTERVAL_TIME,
|
||||
TIMER_RUN_ONE_SHOT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "utils.h"
|
||||
#include "bsp_common.h"
|
||||
|
||||
const char Hex2Ascii[17] = "0123456789ABCDEF";
|
||||
|
||||
int hex_printf (const uint8_t *buff, int count)
|
||||
{
|
||||
uint32_t i = 0, j = 0;
|
||||
|
||||
char str_val[75] = {0};
|
||||
uint32_t index = 0;
|
||||
uint32_t str_index = 0;
|
||||
uint32_t cnt = (count+15)>>4;
|
||||
|
||||
if (count < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cnt > 16) {
|
||||
cnt = 16;
|
||||
//BSP_printf("!!! TOO LONG. ONLY SHOW HEAD 256 bytes !!!\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
index = 0;
|
||||
str_index = 0;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (j + (i << 4) < count) {
|
||||
str_val[index++] = Hex2Ascii[(buff[j + (i << 4)] & 0xF0) >> 4];
|
||||
str_val[index++] = Hex2Ascii[buff[j + (i << 4)] & 0xF];
|
||||
str_val[index++] = ' ';
|
||||
|
||||
} else {
|
||||
str_val[index++] = ' ';
|
||||
str_val[index++] = ' ';
|
||||
str_val[index++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
index += str_index;
|
||||
str_val[index++] = '\0';
|
||||
str_val[index++] = '\0';
|
||||
printf("%s\r\n", str_val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Name: CRC-16/XMODEM x16+x12+x5+1
|
||||
* Poly: 0x1021
|
||||
* Init: 0x0000
|
||||
* Refin: False
|
||||
* Refout: False
|
||||
* Xorout: 0x0000
|
||||
* Alias: CRC-16/ZMODEM,CRC-16/ACORN
|
||||
*****************************************************************************/
|
||||
uint16_t crc16_xmodem (uint8_t *data, uint16_t length)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t crc = 0; // Initial value
|
||||
while(length--)
|
||||
{
|
||||
crc ^= (uint16_t)(*data++) << 8; // crc ^= (uint16_t)(*data)<<8; data++;
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
if ( crc & 0x8000 )
|
||||
crc = (crc << 1) ^ 0x1021;
|
||||
else
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t crc32_step (uint32_t in_crc, const void *buf, uint32_t size)
|
||||
{
|
||||
static uint32_t crc_table[256] = {0, 0,};
|
||||
uint32_t i = 0, j = 0, crc = 0;
|
||||
|
||||
if (!crc_table[1]) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
crc = i;
|
||||
for (j = 0; j < 8; j++) {
|
||||
crc = (crc & 1) ? ((crc>>1)^0xEDB88320ul) : (crc>>1);
|
||||
}
|
||||
crc_table[i] = crc;
|
||||
}
|
||||
}
|
||||
|
||||
crc = in_crc ^ 0xFFFFFFFFul;
|
||||
for (i = 0; i < size; i++) {
|
||||
crc = crc_table[(crc ^ ((const uint8_t *)buf)[i]) & 0xFF]^(crc>>8);
|
||||
}
|
||||
|
||||
return crc ^ 0xFFFFFFFFul;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
|
||||
|
||||
#include "ymodem.h"
|
||||
|
||||
struct ymodem_info_t {
|
||||
uint8_t isBusy; /* 正在处理主机数据的标志位 */
|
||||
uint8_t enRecv; /* 使能接收主机的指令包 */
|
||||
|
||||
uint16_t rxLen; /* 接收到的数据长度 */
|
||||
uint8_t *rxData; /* 协议解析的数据来源 */
|
||||
|
||||
uint8_t numPkt; /* 记录 YModem 协议的 packet number */
|
||||
|
||||
eYmFLOW flow; /* 记录协议的执行流程 */
|
||||
|
||||
union message_raw_t *msg; /* 接收主机数据包的缓存池,称为主机消息 */
|
||||
|
||||
struct tx_raw_t txPkt; /* 用于存放设备上发数据组包的部分参数 */
|
||||
|
||||
ymSend send; /* 数据发送接口 */
|
||||
ymPrepareCallback prepare; /* 收到主机指令时的预备处理接口 */
|
||||
ymReplyCallback reply; /* 正在执行指令时响应主机查询执行过程和结果的接口 */
|
||||
};
|
||||
|
||||
static struct ymodem_info_t yM;
|
||||
|
||||
static struct drv_timer_t timerSendC; /* 用于定时向主机发送数据的定时器 */
|
||||
|
||||
|
||||
|
||||
static void timerSendCCallback (void *user_data)
|
||||
{
|
||||
static uint8_t c[1] = {YMODEM_C};
|
||||
yM.send(c, 1, HAL_MAX_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 复位一些全局变量和标志信息
|
||||
* @note
|
||||
* @retval None
|
||||
*/
|
||||
static void ymodemReset (void)
|
||||
{
|
||||
yM.isBusy = 0;
|
||||
yM.enRecv = 1;
|
||||
yM.numPkt = 0;
|
||||
yM.flow = YMODEM_FLOW_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对主机下发的心跳包的处理
|
||||
* @note 对主机下发的数据帧进行回复, ymodem 没有心跳包,此处只是模拟
|
||||
* @retval None
|
||||
*/
|
||||
static void ymodemHeartBeatProcess (void)
|
||||
{
|
||||
static eRESULT result;
|
||||
|
||||
yM.reply((eYmCMD)yM.msg->pkg.header, &result, NULL, NULL);
|
||||
|
||||
switch (result) {
|
||||
case YM_RESULT_OK:
|
||||
//yM.txPkt.response = YMODEM_ACK;
|
||||
break;
|
||||
|
||||
case YM_RESULT_FAILED: {
|
||||
/* 因前面已经加 1 ,此处是由于对数据处理有问题,非协议本身问题,因此需要减回 */
|
||||
yM.numPkt--;
|
||||
yM.txPkt.response = YMODEM_NAK;
|
||||
break;
|
||||
}
|
||||
|
||||
case YM_RESULT_CANCEL:
|
||||
yM.txPkt.response = YMODEM_CAN;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* 业务层还在处理数据,暂时不回复主机 */
|
||||
return;
|
||||
}
|
||||
|
||||
yM.isBusy = 0;
|
||||
yM.send(&yM.txPkt.response, 1, HAL_MAX_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对主机下发指令的处理
|
||||
* @note
|
||||
* @retval None
|
||||
*/
|
||||
static void ymodemCommandProcess (void)
|
||||
{
|
||||
uint16_t data_len = 0;
|
||||
|
||||
yM.isBusy = 1;
|
||||
|
||||
|
||||
if ((yM.msg->pkg.header == YMODEM_SOH)||(yM.msg->pkg.header == YMODEM_STX)) {
|
||||
data_len = yM.rxLen - YMODEM_FRAME_FIXED_LEN;
|
||||
}
|
||||
|
||||
yM.prepare((eYmCMD)yM.msg->pkg.header, yM.msg->pkg.data, data_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置协议执行流程
|
||||
* @note
|
||||
* @param[in] cmd: 主机的指令
|
||||
* @retval eErrCode
|
||||
*/
|
||||
static eErrCode ymodemExeFlow (eYmCMD cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case YM_CMD_SOH: {
|
||||
if (yM.flow == YMODEM_FLOW_NONE) { /* 第一个 SOH 数据帧 */
|
||||
yM.flow = YMODEM_FLOW_START;
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
} else if (yM.flow == YMODEM_FLOW_SECOND_EOT) { /* 最后一个空的 SOH 数据帧 */
|
||||
drv_timer_pause(&timerSendC);
|
||||
yM.flow = YMODEM_FLOW_SUCCESS;
|
||||
yM.numPkt = 0;
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
} else { /* 正在传输数据的 SOH 数据帧 */
|
||||
/* 暂停发送字符“ C ”的定时器 */
|
||||
drv_timer_pause(&timerSendC);
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case YM_CMD_STX: {
|
||||
/* 因为第一个有数据的数据帧可能是 STX ,因此此处有必要暂停发送字符“ C ”的定时器 */
|
||||
drv_timer_pause(&timerSendC);
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
break;
|
||||
}
|
||||
|
||||
case YM_CMD_EOT: {
|
||||
if (yM.flow == YMODEM_FLOW_START) { /* 第一个 EOT */
|
||||
yM.flow = YMODEM_FLOW_FIRST_EOT;
|
||||
yM.txPkt.response = YMODEM_NAK;
|
||||
} else if (yM.flow == YMODEM_FLOW_FIRST_EOT) { /* 第二个 EOT */
|
||||
yM.flow = YMODEM_FLOW_SECOND_EOT;
|
||||
yM.numPkt = 0;
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
/* 发完 ACK 需要继续发“ C ” */
|
||||
drv_timer_restart(&timerSendC);
|
||||
} else {
|
||||
return ERR_EXE_FLOW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case YM_CMD_CAN: {
|
||||
yM.flow = YMODEM_FLOW_CANCEL;
|
||||
yM.txPkt.response = YMODEM_ACK;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 协议解析处理函数
|
||||
* @note 需要循环调用
|
||||
* @retval eErrCode
|
||||
*/
|
||||
eErrCode ymodemHandler (uint8_t *data, uint16_t len)
|
||||
{
|
||||
eErrCode err_code;
|
||||
|
||||
/* 有数据 */
|
||||
if (data && len && yM.enRecv) {
|
||||
/* 暂存和格式化 */
|
||||
yM.rxData = data;
|
||||
yM.rxLen = len;
|
||||
yM.msg = (union message_raw_t *)yM.rxData;
|
||||
//hex_printf(data, len);
|
||||
/* 只有数据帧才做以下错误检查 */
|
||||
if (yM.msg->pkg.header == YMODEM_SOH || yM.msg->pkg.header == YMODEM_STX) {
|
||||
/* 判断序列号是否符合顺序 */
|
||||
if (yM.msg->pkg.pkt_num != yM.numPkt) {
|
||||
if (yM.msg->pkg.pkt_num == (yM.numPkt - 1)) {
|
||||
printf("error: duplicate frame %d %d\r\n", yM.msg->pkg.pkt_num, yM.numPkt);
|
||||
err_code = ERR_DUPLICATE_FRAME;
|
||||
} else {
|
||||
printf("error: omission frame %d %d\r\n", yM.msg->pkg.pkt_num, yM.numPkt);
|
||||
err_code = ERR_OMISSION_FRAME;
|
||||
}
|
||||
goto __error_exit;
|
||||
}
|
||||
|
||||
/* 判断正反序列号是否正确 */
|
||||
uint8_t pkt_num = ~(yM.msg->pkg.pkt_num);
|
||||
if (yM.msg->pkg.not_pkt_num != pkt_num) {
|
||||
printf("error: packet number: %.2X %.2X\r\n", yM.msg->pkg.pkt_num, yM.msg->pkg.not_pkt_num);
|
||||
err_code = ERR_PKT_NUM_ERR;
|
||||
goto __error_exit;
|
||||
}
|
||||
|
||||
/* 获取协议帧中的数据字段长度 */
|
||||
uint16_t data_len;
|
||||
if (yM.msg->pkg.header == YMODEM_SOH) {
|
||||
data_len = YMODEM_SOH_DATA_LEN;
|
||||
} else if (yM.msg->pkg.header == YMODEM_STX) {
|
||||
data_len = YMODEM_STX_DATA_LEN;
|
||||
}
|
||||
|
||||
/* 帧长度判断 */
|
||||
/* 奇怪的是, Xshell 在发送最后一个空 SOH 数据帧时会附加两个字节的 0x4F ,原因未知。
|
||||
* 为了处理这个问题,避免误判为数据帧长度有误,此处嵌套了“ ymodem_pkt_num != 0 ”的判断 */
|
||||
if (yM.numPkt != 0) {
|
||||
if (yM.rxLen != (data_len + YMODEM_FRAME_FIXED_LEN)) {
|
||||
//printf("error: _dev_rx_len: %d\r\n", yM.rxLen);
|
||||
err_code = ERR_FRAME_LENGTH;
|
||||
goto __error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* 校验数据是否正确 */
|
||||
uint16_t crc16 = crc16_xmodem(yM.msg->pkg.data, data_len);
|
||||
printf("%04X", crc16);
|
||||
uint16_t raw_crc16 = (yM.msg->pkg.data[data_len] << 8) | yM.msg->pkg.data[data_len + 1];
|
||||
if (crc16 != raw_crc16) {
|
||||
printf("error: crc16: %.4X\r\n", crc16);
|
||||
printf("error: raw crc16: %.4X\r\n", raw_crc16);
|
||||
err_code = ERR_FRAME_VERIFY_ERR;
|
||||
goto __error_exit;
|
||||
}
|
||||
//printf("crc16 ok.\r\n");
|
||||
|
||||
/* 执行到此处记录序列号加1 */
|
||||
yM.numPkt++;
|
||||
}
|
||||
//printf("Ymodem recv len: %d (%02X %02X %02X)\r\n",
|
||||
// yM.rxLen, yM.msg->pkg.header, yM.msg->pkg.pkt_num, yM.msg->pkg.not_pkt_num);
|
||||
|
||||
/* 设置流程 */
|
||||
if (ymodemExeFlow((eYmCMD)yM.msg->pkg.header)) {
|
||||
//printf("error: flow illegal\r\n");
|
||||
err_code = ERR_EXE_FLOW;
|
||||
goto __error_exit;
|
||||
}
|
||||
|
||||
/* 除了最后一个空的SOH数据帧,其他都会执行 ,包括 EOT CAN */
|
||||
/* 需要注意是, 执行完后仍未回复主机,回复部分由 ymodemHeartBeatProcess 处理 */
|
||||
ymodemCommandProcess();
|
||||
return ERR_OK;
|
||||
|
||||
__error_exit:
|
||||
|
||||
yM.txPkt.response = YMODEM_NAK;
|
||||
yM.send(&yM.txPkt.response, 1, HAL_MAX_DELAY);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
if (yM.isBusy) {
|
||||
/* 模拟主机的心跳处理,查询是否对协议包处理完毕,以向主机回复 */
|
||||
ymodemHeartBeatProcess();
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 配置协议析构层的参数
|
||||
* @note
|
||||
* @param[in] para: 需要进行配置的选型或参数
|
||||
* @param[in] value: 对应的数据或值
|
||||
* @retval None
|
||||
*/
|
||||
void ymodemConfig (eYmMODE mode, void *value)
|
||||
{
|
||||
switch (mode) {
|
||||
case YM_MODE_RESET:
|
||||
ymodemReset();
|
||||
drv_timer_restart(&timerSendC);
|
||||
break;
|
||||
|
||||
case YM_MODE_RECV: {
|
||||
uint8_t *enable = (uint8_t *)value;
|
||||
yM.enRecv = *enable;
|
||||
if (yM.enRecv == 0) {
|
||||
drv_timer_pause(&timerSendC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 协议析构层的初始化
|
||||
* @note
|
||||
* @param[in] Send: 底层数据发送接口
|
||||
* @param[in] HeartbeatCallback: 心跳包的响应接口
|
||||
* @param[in] PrepareCallback: 指令包的处理接口
|
||||
* @param[in] Set_ReplyInfo: 查询指令执行结果的处理接口
|
||||
* @retval None
|
||||
*/
|
||||
void ymodem_init (ymSend Send,
|
||||
ymPrepareCallback PrepareCallback,
|
||||
ymReplyCallback Set_ReplyInfo)
|
||||
{
|
||||
yM.send = Send;
|
||||
yM.prepare = PrepareCallback;
|
||||
yM.reply = Set_ReplyInfo;
|
||||
|
||||
ymodemReset();
|
||||
|
||||
drv_timer_init(&timerSendC,
|
||||
timerSendCCallback,
|
||||
1000,
|
||||
TIMER_RUN_FOREVER);
|
||||
drv_timer_start(&timerSendC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef _AES_H_
|
||||
#define _AES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// #define the macros below to 1/0 to enable/disable the mode of operation.
|
||||
//
|
||||
// CBC enables AES encryption in CBC-mode of operation.
|
||||
// CTR enables encryption in counter-mode.
|
||||
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
|
||||
|
||||
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
|
||||
#ifndef CBC
|
||||
#define CBC 1
|
||||
#endif
|
||||
|
||||
#ifndef ECB
|
||||
#define ECB 0
|
||||
#endif
|
||||
|
||||
#ifndef CTR
|
||||
#define CTR 0
|
||||
#endif
|
||||
|
||||
|
||||
//#define AES128 1
|
||||
//#define AES192 1
|
||||
#define AES256 1
|
||||
|
||||
#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define AES_KEYLEN 32
|
||||
#define AES_keyExpSize 240
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define AES_KEYLEN 24
|
||||
#define AES_keyExpSize 208
|
||||
#else
|
||||
#define AES_KEYLEN 16 // Key length in bytes
|
||||
#define AES_keyExpSize 176
|
||||
#endif
|
||||
|
||||
struct AES_ctx
|
||||
{
|
||||
uint8_t RoundKey[AES_keyExpSize];
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
uint8_t Iv[AES_BLOCKLEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||
#endif
|
||||
|
||||
#if defined(ECB) && (ECB == 1)
|
||||
// buffer size is exactly AES_BLOCKLEN bytes;
|
||||
// you need only AES_init_ctx as IV is not used in ECB
|
||||
// NB: ECB is considered insecure for most uses
|
||||
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||
|
||||
#endif // #if defined(ECB) && (ECB == !)
|
||||
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
|
||||
#endif // #if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
#if defined(CTR) && (CTR == 1)
|
||||
|
||||
// Same function for encrypting as for decrypting.
|
||||
// IV is incremented for every block, and used after encryption as XOR-compliment for output
|
||||
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
|
||||
#endif // #if defined(CTR) && (CTR == 1)
|
||||
|
||||
|
||||
#endif // _AES_H_
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef __APP_H__
|
||||
#define __APP_H__
|
||||
|
||||
#include "firmware.h"
|
||||
#include "ymodem.h"
|
||||
#include "transfer.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
EXE_FLOW_NOTHING = 0x00,
|
||||
EXE_FLOW_ACCIDENT_UPDATE, /* 意外更新固件流程 */
|
||||
EXE_FLOW_NEED_HOST_SEND_FIRMWARE, /* 需要主机下发固件包 */
|
||||
|
||||
EXE_FLOW_FIND_RUNNING_FIRMWARE, /* (0) 在各分区查找可运行的固件 */
|
||||
EXE_FLOW_WAIT_FIRMWARE, /* 等待接收固件包 */
|
||||
EXE_FLOW_VERIFY_FIRMWARE_HEAD, /* (1) 校验收到的固件包头 */
|
||||
EXE_FLOW_ERASE_OLD_FIRMWARE, /* 擦除旧固件 */
|
||||
EXE_FLOW_ERASE_OLD_FIRMWARE_DONE, /* 完成擦除旧固件 */
|
||||
EXE_FLOW_WRITE_FIRMWARE_HEAD, /* 将固件包头写入 flash */
|
||||
EXE_FLOW_WRITE_FIRMWARE_HEAD_DONE, /* 完成固件包头的写入 */
|
||||
EXE_FLOW_VERIFY_FIRMWARE_PKG, /* (2) 校验固件分包数据的正确性 */
|
||||
EXE_FLOW_WRITE_NEW_FIRMWARE, /* 写入新的固件分包到分区 */
|
||||
EXE_FLOW_WRITE_NEW_FIRMWARE_DONE, /* 写入新的固件分包完成 */
|
||||
EXE_FLOW_UPDATE_FIRMWARE, /* (3) 开始更新固件 */
|
||||
EXE_FLOW_VERIFY_FIRMWARE, /* 校验整个固件包体的数据正确性 */
|
||||
EXE_FLOW_VERIFY_FIRMWARE_DONE, /* 完成校验整个固件包体的数据正确性 */
|
||||
EXE_FLOW_ERASE_APP, /* 擦除 APP 分区的固件 */
|
||||
EXE_FLOW_UPDATE_TO_APP, /* 将其它分区的固件更新到 APP 分区 */
|
||||
EXE_FLOW_VERIFY_APP, /* 校验 APP 分区固件的数据正确性 */
|
||||
EXE_FLOW_UPDATE_TO_APP_DONE, /* 校验 APP 分区固件通过后,将剩余数据写入 */
|
||||
EXE_FLOW_ERASE_DOWNLOAD, /* 擦除 download 分区 */
|
||||
EXE_FLOW_ERASE_DOWNLOAD_DONE, /* 完成擦除 download 分区 */
|
||||
EXE_FLOW_JUMP_TO_APP, /* 跳转至 APP 运行 */
|
||||
EXE_FLOW_RECOVERY, /* 恢复出厂固件 */
|
||||
EXE_FLOW_FAILED, /* 失败流程 */
|
||||
} eFLOW;
|
||||
|
||||
|
||||
/* 固件更新的缩略步骤,用于计算固件更新的进度 */
|
||||
typedef enum {
|
||||
STEP_VERIFY_FIRMWARE = 0x00, /* 校验接收到的固件包 */
|
||||
STEP_ERASE_APP, /* 擦除 APP 分区 */
|
||||
STEP_UPDATE_TO_APP, /* 更新固件包到 APP 分区 */
|
||||
STEP_VERIFY_APP, /* 校验 APP 固件 */
|
||||
STEP_ERASE_DOWNLOAD, /* 擦除 download 分区 */
|
||||
|
||||
} eSTAGE;
|
||||
|
||||
|
||||
/* 应用状态 */
|
||||
typedef enum {
|
||||
BOOT_STATUS_NONE = 0x00,
|
||||
BOOT_STATUS_NO_UPDATE, /* 无须更新固件的标志 */
|
||||
BOOT_STATUS_ENTER_UPDATE_MODE, /* 进入固件更新模式的标志 */
|
||||
BOOT_STATUS_ACCIDENT_UPDATE, /* 意外更新固件中 */
|
||||
BOOT_STATUS_UPDATE_SUCCESS, /* 更新固件成功 */
|
||||
BOOT_STATUS_UPDATE_FAILED, /* 更新固件失败 */
|
||||
BOOT_STATUS_NO_FIRMWARE, /* 无任何可用固件 */
|
||||
BOOT_STATUS_NO_APP, /* 无 APP 固件 */
|
||||
BOOT_STATUS_READ_PART_ERR, /* 读取分区失败 */
|
||||
BOOT_STATUS_APP_VERIFY_ERR, /* APP 固件校验错误 */
|
||||
BOOT_STATUS_APP_CAN_NOT_VERIFY, /* APP 固件无法校验 */
|
||||
BOOT_STATUS_AUTO_UPDATE_FAILED, /* 自动更新失败 */
|
||||
|
||||
} eSTATE;
|
||||
|
||||
struct upgrade_t {
|
||||
eSTATE state; /* 记录 bootloader 所处的状态 */
|
||||
eFLOW flow; /* 应用执行的流程 */
|
||||
eSTAGE stage; /* 固件的更新阶段,便于程序判断 progress 的增加系数 */
|
||||
|
||||
eRESULT result; /* 指令执行结果 */
|
||||
eErrCode errCode; /* 指令执行失败时的故障码 */
|
||||
|
||||
uint8_t start :1; /* 开始固件更新流程的标志 */
|
||||
uint8_t :0;
|
||||
|
||||
uint8_t progress; /* 固件更新的总进度, 0-100 */
|
||||
};
|
||||
|
||||
extern void System_Init (void);
|
||||
|
||||
extern void APP_Init (void);
|
||||
|
||||
extern void APP_Running (void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
#ifndef __APP_CONFIG_H__
|
||||
#define __APP_CONFIG_H__
|
||||
|
||||
|
||||
#define VERSION_MAIN 1
|
||||
#define VERSION_SUB 0
|
||||
#define VERSION_FIX 0
|
||||
#define BOOT_VERSION ((VERSION_MAIN<<16)|(VERSION_SUB<<8)|VERSION_FIX)
|
||||
#define BUILD_TIMESTAMP __DATE__", "__TIME__
|
||||
|
||||
#define NAME_PART_APPLICATION "app"
|
||||
#define NAME_PART_DOWNLOAD "download"
|
||||
#define NAME_PART_FACTORY "factory"
|
||||
|
||||
/** 配置各个分区的大小
|
||||
需页对齐, 分区首地址必须是 Flash 的 每个独立 page 或 sector 的首地址,否则固件无法运行
|
||||
*/
|
||||
#if defined(STM32F405xx)
|
||||
#define NAME_CHIP "STM32F405xx"
|
||||
#define SIZE_ONCHIP_FLASH (1024 * 1024ul) // 片上 flash 总容量
|
||||
#else
|
||||
#error "no chip size defined"
|
||||
#endif
|
||||
|
||||
#define SIZE_PART_BOOTLOADER (64 * 1024ul) // bootloader 占用空间(需要大于本程序bin大小)
|
||||
#define SIZE_PART_PARAMETERS (64 * 1024ul) // 参数 占用空间
|
||||
#define SIZE_PART_LOG (128 * 1024ul) // 日志 占用空间
|
||||
#define SIZE_PART_APPLICATION (SIZE_ONCHIP_FLASH/4) // app 占用空间
|
||||
#define SIZE_PART_DOWNLOAD (SIZE_PART_APPLICATION) // download 占用空间
|
||||
#define SIZE_PART_FACTORY (SIZE_PART_APPLICATION) // factory 占用空间
|
||||
|
||||
#define BASE_ONCHIP_FLASH (FLASH_BASE) // on chip flash 首地址
|
||||
#define OFFSET_ONCHIP_FLASH_END (BASE_ONCHIP_FLASH + SIZE_ONCHIP_FLASH)
|
||||
/*
|
||||
chipsize eg: 1024KB
|
||||
64KB - bootloader = 0x00000 + 64*1024
|
||||
64KB - parameter = 0x10000 + 64*1024
|
||||
128KB - log = 0x20000 + 128*1024
|
||||
256KB - application = 0x40000 + 256*1024
|
||||
256KB - download = 0x80000 + 256*1024
|
||||
256KB - factory = 0xC0000 + 256*1024
|
||||
*/
|
||||
#define BASE_BOOTLOADER (BASE_ONCHIP_FLASH)
|
||||
#define BASE_PARAMETERS (BASE_BOOTLOADER + SIZE_PART_BOOTLOADER) // 参数分区起始地址
|
||||
#define BASE_LOG (BASE_PARAMETERS + SIZE_PART_PARAMETERS)
|
||||
#define BASE_APPLICATION (BASE_ONCHIP_FLASH + SIZE_PART_BOOTLOADER+SIZE_PART_PARAMETERS+SIZE_PART_LOG) // app 分区起始地址
|
||||
#define BASE_DOWNLOAD (BASE_ONCHIP_FLASH + SIZE_ONCHIP_FLASH/2) // download 分区起始地址
|
||||
#define BASE_FACTORY (BASE_DOWNLOAD + SIZE_PART_DOWNLOAD) // factory 分区起始地址
|
||||
|
||||
/* 片上分区数量选项
|
||||
* app: 可运行的固件区域
|
||||
* download: 用于更新固件时的固件临时存放区域
|
||||
* factory: 用于存放可在紧急情况下恢复固件使用的区域
|
||||
*/
|
||||
#define USE_SINGLE_PARTITION 0 // 单分区方案 仅 app
|
||||
#define USE_DOUBLE_PARTITION 1 // 双分区方案 含 app + download
|
||||
#define USE_TRIPLE_PARTITION 2 // 三分区方案 含 app + download + factory
|
||||
|
||||
#define CONFIG_CHIP_PARTS USE_TRIPLE_PARTITION
|
||||
|
||||
|
||||
#define ENABLE_ASSERT 0 /* 是否使能函数入口参数检查 */
|
||||
#define ENABLE_DEBUG_PRINT 1 /* 是否使能调试信息打印 */
|
||||
|
||||
#define MAX_NAME_LEN 8
|
||||
|
||||
|
||||
|
||||
// 本 bootloader 运行窗口最小时间
|
||||
#define CONFIG_TIMEOUT_HOST_START (5*1000) // 设置等待主机数据的最大等待时间,单位 ms
|
||||
|
||||
#define CONFIG_DECRYPT 1
|
||||
#if (CONFIG_DECRYPT)
|
||||
// 以下同步给 upk 打包工具
|
||||
#define AES256_KEY "0123456789ABCDEF0123456789ABCDEF" // 必须是 32 字节
|
||||
#define AES256_IV "0123456789ABCDEF" // 必须是 16 字节
|
||||
#endif
|
||||
|
||||
|
||||
/* 判断固件包是否超过分区大小 */
|
||||
#define CONFIG_CHECK_SIZE 1
|
||||
|
||||
|
||||
/* 单次写入的最小字节数*/
|
||||
#define CONFIG_WRITE_BYTES_LEASET 4
|
||||
|
||||
|
||||
/* 自动更新固件的处理选项
|
||||
* 1. 在固件更新过程中设备异常断电或重启后,选择是否自动更新已下载好的固件以及自动更新的处理方案
|
||||
* 2. 该选项的执行优先级低于上位机更新的方式,这意味着除非上位机超时未发送数据,否则将会优先执行上位机的固件更新
|
||||
*
|
||||
* MODE_NOT_AUTO_UPDATE: 不需要自动更新,不希望有这种断电恢复固件的机制
|
||||
* MODE_CLEAR_DOWNLOAD_PART: 更新完成后擦除 download 分区。设备上电时会通过检测 download 分区有无可用固件
|
||||
* 以判断是否需要自动更新固件
|
||||
* 选择此方案后,将无法选择是否在上电后对 APP 的固件进行安规校验( CONFIG_CHECK_APP_SECURITY )。
|
||||
* 因为 APP 固件安规校验的数据来源是 download 分区的固件包。
|
||||
* MODE_UPDATE_DOWNLOAD_HEAD: 更新完成后修改 download 分区的固件表头的版本信息。设备上电时会对比 download 分区固件包头记录的新旧版本,
|
||||
* 若新旧版本不一致,则开始自动更新固件
|
||||
* 此种方式需要修改 download 分区的数据,有以下优劣势:
|
||||
* 1. 优势:上电时可校验 APP 分区的固件数据正确性和完整性,以提高 APP 固件有损坏或遭篡改时的安全性,甚至
|
||||
* 可以将固件恢复正常,有效提高系统的安全等级
|
||||
* 2. 劣势:需要对表头所在的 flash sector 擦除后再重新写入,这意味着每次更新都会擦除同个 sector 两次。
|
||||
* MODE_APPEND_TO_APP: 更新完成后将新的固件版本写进 APP 分区的尾部,占用 16 byte ,设备上电时会对比 download 分区固件包头
|
||||
* 记录的版本和 APP 存放的版本,若两个版本不一致,则开始自动更新固件
|
||||
* 此种方式有以下优劣势:
|
||||
* 1. 优势:上电时可校验 APP 分区的固件数据正确性和完整性,以提高 APP 固件有损坏或遭篡改时的安全性,甚至
|
||||
* 可以将固件恢复正常,有效提高系统的安全等级
|
||||
* 2. 劣势:需要占用 APP 分区 16 byte 的空间
|
||||
*/
|
||||
#define MODE_NOT_AUTO_UPDATE 0
|
||||
#define MODE_CLEAR_DOWNLOAD_PART 1
|
||||
#define MODE_UPDATE_DOWNLOAD_HEAD 2
|
||||
#define MODE_APPEND_TO_APP 3
|
||||
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
#define CONFIG_AUTO_UPDATE_MODE MODE_APPEND_TO_APP
|
||||
#endif
|
||||
|
||||
|
||||
/** 是否在上电后对 APP 的固件进行安规校验 及 APP 固件检查有问题时的操作
|
||||
* 1. CONFIG_AUTO_UPDATE_MODE = MODE_UPDATE_DOWNLOAD_HEAD 时,本配置才会起效
|
||||
* 2. 部分产品对固件的完整性有安规等级要求,本组件支持 APP 固件的数据完整性检查,通过配置以选择是否启用
|
||||
* 3. 当启用时,通过配置 USING_APP_SAFETY_PROJECT 可选择 APP 固件检查有问题时的操作方案
|
||||
* DO_NOT_CHECK : 不校验 APP 固件,即不启用
|
||||
* CHECK_UNLESS_EMPTY: 校验 APP 固件,但无法校验时不校验,确保能运行 APP 而不至于等在 bootloader 中。若 APP 固件校验错误,将会
|
||||
* 自动把可用和正确的固件更新至 APP
|
||||
* * 无法进行 APP 固件校验的情况是: download 分区和 factory 分区均无可用固件包
|
||||
* AUTO_UPDATE_APP : APP 固件校验错误后自动将可用和正确的固件更新至 APP
|
||||
* * 需要注意的是,当选择了本选项,意味着你十分重视 APP 的数据完整性,也就是说,当 APP 固件校验不通过或
|
||||
* 无法校验时,若 download 分区和 factory 分区均无可用固件包,则会停留在 bootloader 中,不会跳转至 APP ,
|
||||
* 即便 APP 存在固件
|
||||
* * 需要特别声明的是,有一种情况会导致 APP 无法被执行,那便是通过烧录器将固件烧录进 MCU 的 flash 中,
|
||||
* 因为此时不是通过正常的固件更新程序执行, download 分区和 factory 分区均无可用固件包, APP 固件无法进行
|
||||
* 完整性校验,建议采用正常的固件更新流程,即由 bootloader 处理固件更新,或选择 CHECK_UNLESS_EMPTY 选型
|
||||
* * 此处的自动更新和 CONFIG_AUTO_UPDATE_MODE 的不同,本选项仅在 APP 固件校验不通过时才会
|
||||
* 自动更新,而 CONFIG_AUTO_UPDATE_MODE 则是无视本选项进行固件自动更新
|
||||
* DO_NOT_DO_ANYTHING: APP固件校验错误后不要做任何操作,停在 bootloader 即可,即便 download 分区或 factory 分区有可用的固件包
|
||||
* * 需要注意的是, DO_NOT_DO_ANYTHING 这个选项并不能阻止 APP 分区为空时且 CONFIG_AUTO_UPDATE_MODE 启用了
|
||||
* 自动更新的情况, DO_NOT_DO_ANYTHING 只能阻拦APP分区不为空且校验不通过的情况,要阻止自动更新,需要修改
|
||||
* 上方的 CONFIG_AUTO_UPDATE_MODE 选项为 DO_NOT_AUTO_UPDATE
|
||||
*/
|
||||
#define DO_NOT_CHECK 0
|
||||
#define CHECK_UNLESS_EMPTY 1
|
||||
#define AUTO_UPDATE_APP 2
|
||||
#define DO_NOT_DO_ANYTHING 3
|
||||
|
||||
#if ((CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION) \
|
||||
&&((CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD) \
|
||||
||(CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP)))
|
||||
#define CONFIG_CHECK_APP_SECURITY CHECK_UNLESS_EMPTY
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* 【选择是否可以使用 factory 分区的固件包】
|
||||
* 说明:
|
||||
* 当启用自动更新或校验 APP 固件完整性时,若 APP 固件不可用,且 download 分区没有可用的固件时,假设有 factory 分区,
|
||||
* 且 factory 分区有可用的固件,选择是否将 factory 的固件更新至 APP 中
|
||||
* 选项:
|
||||
* 0: 不使用
|
||||
* 1: 使用
|
||||
*/
|
||||
#if ((CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION) \
|
||||
&&((CONFIG_CHECK_APP_SECURITY == CHECK_UNLESS_EMPTY) \
|
||||
||(CONFIG_CHECK_APP_SECURITY == AUTO_UPDATE_APP)))
|
||||
#define CONFIG_FACTORY_RESTORE 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/** 是否自动纠正固件的分区
|
||||
* 说明:
|
||||
* 该选项是为了修正人为的将分区名写错的情况,是一种能最大程度保证固件更新正常的挽救措施
|
||||
* 单分区方案下,无论本功能是否启用,固件包指定的其它分区名都会被修正为 APP 分区,使其可以正常更新
|
||||
* 多分区方案下,启用后,固件包指定为 APP 分区时将会被修正为 download 分区,使其可以正常更新
|
||||
* 多分区方案下,若不启用,固件包指定为 APP 分区时将会报错,并标记为更新失败
|
||||
* 选项:
|
||||
* 0: 不启用
|
||||
* 1: 启用
|
||||
*/
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
#define CONFIG_AUTO_CORRECT 1
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* 【选择是否使用按键恢复出厂固件的选项】
|
||||
* 说明:
|
||||
* 1. 使用本选项的前提是三分区方案,本选项能起效的前提是正确配置了按键且 factory 分区有可用的固件
|
||||
* 2. 选择使用按键恢复出厂固件时,需要配置按键的引脚,如使用的按键和本案例不同,则需要自己配置和初始化 GPIO
|
||||
* 3. 本选项仅设备在运行 bootloader 时,可通过按键恢复出厂固件,若设备运行着 APP ,则本选项是无法起效的,因此需要 APP 也同步配置
|
||||
* 4. 本选项和通过指令恢复出厂固件的方式不冲突,可以同时使用,也可以不启用本选项
|
||||
* 5. 当无 factory 或 factory 无可用固件时,强行恢复出厂固件,将会触发 FACTORY_NO_FIRMWARE_SOLUTION 选项
|
||||
* 解释:
|
||||
* ENABLE_FACTORY_FIRMWARE_BUTTON: 选择是否启用长按按键恢复出厂固件
|
||||
* FACTORY_FIRMWARE_BUTTON_PRESS: 按键按下时的电平逻辑
|
||||
* FACTORY_FIRMWARE_BUTTON_TIME: 按键长按的持续时间,单位 ms
|
||||
* 选项:
|
||||
* ENABLE_FACTORY_FIRMWARE_BUTTON 选项:
|
||||
* 0: 不启用
|
||||
* 1: 启用
|
||||
* FACTORY_FIRMWARE_BUTTON_PRESS 选项:
|
||||
* KEY_PRESS_LOW: 表示按下时为低电平
|
||||
* KEY_PRESS_HIGH: 表示按下时为高电平
|
||||
* FACTORY_FIRMWARE_BUTTON_TIME 选项:
|
||||
* 按键长按的持续时间,单位 ms ,不能大于 65535
|
||||
*/
|
||||
#if (CONFIG_CHIP_PARTS == USE_TRIPLE_PARTITION)
|
||||
#define ENABLE_FACTORY_FIRMWARE_BUTTON 0
|
||||
#define FACTORY_FIRMWARE_BUTTON_PRESS KEY_PRESS_LOW
|
||||
#define FACTORY_FIRMWARE_BUTTON_TIME 3000
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* 【片内 Flash 放置固件包所在 sector 的擦除粒度 ( TODO: 暂未实现 )】
|
||||
* 说明:
|
||||
* CONFIG_AUTO_UPDATE_MODE = MODE_UPDATE_DOWNLOAD_HEAD 时,需要给出固件包所在 sector 的擦除粒度,单位是 byte
|
||||
*/
|
||||
#if (CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD)
|
||||
#define ONCHIP_FLASH_ERASE_GRANULARITY UPK_LEAST_HANDLE_BYTE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
#ifndef __FIRMWARE_MANAGE_H__
|
||||
#define __FIRMWARE_MANAGE_H__
|
||||
|
||||
#include "bsp_common.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* upk: upgrade Package */
|
||||
#define UPK_LEAST_HANDLE_BYTE 4096
|
||||
#define UPK_VERSION_SIZE 16
|
||||
#define UPK_USER_STRING_SIZE 16
|
||||
#define UPK_PART_NAME_SIZE 16
|
||||
#define UPK_HEAD_SIZE sizeof(struct upk_head_t)
|
||||
#define UPK_IDENTIFIER 0x006B7075 // 'upk'
|
||||
|
||||
|
||||
/* 固件写入的方向 */
|
||||
typedef enum
|
||||
{
|
||||
FM_DIR_HOST_TO_APP = 0x00, /* 从主机方向将固件写入 APP 分区 */
|
||||
FM_DIR_HOST_TO_DOWNLOAD, /* 从主机方向将固件写入 download/factory 分区 */
|
||||
FM_DIR_DOWNLOAD_TO_APP, /* 从 download/factory 分区方向将固件写入 APP 分区 */
|
||||
|
||||
} FM_FIRMWARE_WRITE_DIR;
|
||||
|
||||
#pragma pack(1)
|
||||
/* upk 固件表头的内容详见《upk固件包表头信息.xlsx》 */
|
||||
struct upk_head_t {
|
||||
char name[4]; /* upk 文件标识 */
|
||||
uint8_t config[4]; /* 配置选项 */
|
||||
char fw_old_ver[UPK_VERSION_SIZE]; /* 固件旧版本 */
|
||||
char fw_new_ver[UPK_VERSION_SIZE]; /* 固件新版本 */
|
||||
char user_string[UPK_USER_STRING_SIZE]; /* 用户自定义的字符水印 */
|
||||
char part_name[UPK_PART_NAME_SIZE]; /* 固件包存放的分区名 */
|
||||
uint32_t raw_size; /* 源固件的大小,不包含本表头 */
|
||||
uint32_t pkg_size; /* 打包后固件的大小,不包含本表头 */
|
||||
uint32_t timestamp; /* 打包时的 unix 时间戳,可转换为年月日时分秒信息 */
|
||||
uint32_t raw_crc; /* 源固件的 CRC32 值 */
|
||||
uint32_t pkg_crc; /* 打包后固件的 CRC32 值 */
|
||||
uint32_t head_crc; /* 本表头的 CRC32 值 */
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
void FM_Init (void);
|
||||
uint8_t FM_IsEncrypt (void);
|
||||
eErrCode FM_IsEmpty (const char *part_name);
|
||||
char * FM_GetNewFirmwareVersion (void);
|
||||
uint32_t FM_GetRawCRC32 (void);
|
||||
eErrCode FM_StorageFirmwareHead (const char *part_name, uint8_t *data);
|
||||
eErrCode FM_VerifyFirmware (const char *part_name, uint32_t crc32, uint8_t is_auto_fill);
|
||||
eErrCode FM_EraseFirmware (const char *part_name);
|
||||
eErrCode FM_WriteFirmwareDone (const char *part_name);
|
||||
eErrCode FM_WriteFirmwareSubPackage (const char *part_name, uint8_t *data, uint16_t pkg_size);
|
||||
eErrCode FM_CheckFirmwareIntegrity (uint32_t addr);
|
||||
|
||||
#if (CONFIG_CHIP_PARTS > USE_SINGLE_PARTITION)
|
||||
uint8_t FM_IsNeedAutoUpdate (void);
|
||||
char * FM_GetPartName (void);
|
||||
char * FM_GetOldFirmwareVersion (void);
|
||||
uint32_t FM_GetPackageCRC32 (void);
|
||||
eErrCode FM_ReadFirmwareHead (const char *part_name);
|
||||
eErrCode FM_UpdateToAPP (const char *from_part_name);
|
||||
#if (CONFIG_AUTO_UPDATE_MODE == MODE_UPDATE_DOWNLOAD_HEAD || \
|
||||
CONFIG_AUTO_UPDATE_MODE == MODE_APPEND_TO_APP)
|
||||
eErrCode FM_UpdateFirmwareVersion (const char *part_name);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef __MAIN_H
|
||||
#define __MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
|
||||
|
||||
#if defined(STM32F405xx)
|
||||
#define KEY0_Pin GPIO_PIN_8
|
||||
#define KEY0_GPIO_Port GPIOC
|
||||
|
||||
#define LED0_Pin GPIO_PIN_13
|
||||
#define LED0_GPIO_Port GPIOC
|
||||
#elif defined(STM32F411xE)||defined(STM32F401xC)
|
||||
#define KEY0_Pin GPIO_PIN_0
|
||||
#define KEY0_GPIO_Port GPIOA
|
||||
|
||||
#define LED0_Pin GPIO_PIN_13
|
||||
#define LED0_GPIO_Port GPIOC
|
||||
#endif
|
||||
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,490 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_hal_conf_template.h
|
||||
* @author MCD Application Team
|
||||
* @brief HAL configuration template file.
|
||||
* This file should be copied to the application folder and renamed
|
||||
* to stm32f4xx_hal_conf.h.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_HAL_CONF_H
|
||||
#define __STM32F4xx_HAL_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* ########################## Module Selection ############################## */
|
||||
/**
|
||||
* @brief This is the list of modules to be used in the HAL driver
|
||||
*/
|
||||
#define HAL_MODULE_ENABLED
|
||||
|
||||
/* #define HAL_CRYP_MODULE_ENABLED */
|
||||
/* #define HAL_ADC_MODULE_ENABLED */
|
||||
/* #define HAL_CAN_MODULE_ENABLED */
|
||||
/* #define HAL_CRC_MODULE_ENABLED */
|
||||
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
/* #define HAL_DAC_MODULE_ENABLED */
|
||||
/* #define HAL_DCMI_MODULE_ENABLED */
|
||||
/* #define HAL_DMA2D_MODULE_ENABLED */
|
||||
/* #define HAL_ETH_MODULE_ENABLED */
|
||||
/* #define HAL_NAND_MODULE_ENABLED */
|
||||
/* #define HAL_NOR_MODULE_ENABLED */
|
||||
/* #define HAL_PCCARD_MODULE_ENABLED */
|
||||
/* #define HAL_SRAM_MODULE_ENABLED */
|
||||
/* #define HAL_SDRAM_MODULE_ENABLED */
|
||||
/* #define HAL_HASH_MODULE_ENABLED */
|
||||
/* #define HAL_I2C_MODULE_ENABLED */
|
||||
/* #define HAL_I2S_MODULE_ENABLED */
|
||||
/* #define HAL_IWDG_MODULE_ENABLED */
|
||||
/* #define HAL_LTDC_MODULE_ENABLED */
|
||||
/* #define HAL_RNG_MODULE_ENABLED */
|
||||
/* #define HAL_RTC_MODULE_ENABLED */
|
||||
/* #define HAL_SAI_MODULE_ENABLED */
|
||||
/* #define HAL_SD_MODULE_ENABLED */
|
||||
/* #define HAL_MMC_MODULE_ENABLED */
|
||||
/* #define HAL_SPI_MODULE_ENABLED */
|
||||
/* #define HAL_TIM_MODULE_ENABLED */
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
/* #define HAL_USART_MODULE_ENABLED */
|
||||
/* #define HAL_IRDA_MODULE_ENABLED */
|
||||
/* #define HAL_SMARTCARD_MODULE_ENABLED */
|
||||
/* #define HAL_SMBUS_MODULE_ENABLED */
|
||||
/* #define HAL_WWDG_MODULE_ENABLED */
|
||||
/* #define HAL_PCD_MODULE_ENABLED */
|
||||
/* #define HAL_HCD_MODULE_ENABLED */
|
||||
/* #define HAL_DSI_MODULE_ENABLED */
|
||||
/* #define HAL_QSPI_MODULE_ENABLED */
|
||||
/* #define HAL_QSPI_MODULE_ENABLED */
|
||||
/* #define HAL_CEC_MODULE_ENABLED */
|
||||
/* #define HAL_FMPI2C_MODULE_ENABLED */
|
||||
/* #define HAL_FMPSMBUS_MODULE_ENABLED */
|
||||
/* #define HAL_SPDIFRX_MODULE_ENABLED */
|
||||
/* #define HAL_DFSDM_MODULE_ENABLED */
|
||||
/* #define HAL_LPTIM_MODULE_ENABLED */
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#define HAL_EXTI_MODULE_ENABLED
|
||||
#define HAL_DMA_MODULE_ENABLED
|
||||
#define HAL_RCC_MODULE_ENABLED
|
||||
#define HAL_FLASH_MODULE_ENABLED
|
||||
#define HAL_PWR_MODULE_ENABLED
|
||||
#define HAL_CORTEX_MODULE_ENABLED
|
||||
|
||||
/* ########################## HSE/HSI Values adaptation ##################### */
|
||||
/**
|
||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
|
||||
#endif /* HSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief Internal High Speed oscillator (HSI) value.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSI is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @brief Internal Low Speed oscillator (LSI) value.
|
||||
*/
|
||||
#if !defined (LSI_VALUE)
|
||||
#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz*/
|
||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||
The real value may vary depending on the variations
|
||||
in voltage and temperature.*/
|
||||
/**
|
||||
* @brief External Low Speed oscillator (LSE) value.
|
||||
*/
|
||||
#if !defined (LSE_VALUE)
|
||||
#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
|
||||
#endif /* LSE_VALUE */
|
||||
|
||||
#if !defined (LSE_STARTUP_TIMEOUT)
|
||||
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
|
||||
#endif /* LSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief External clock source for I2S peripheral
|
||||
* This value is used by the I2S HAL module to compute the I2S clock source
|
||||
* frequency, this source is inserted directly through I2S_CKIN pad.
|
||||
*/
|
||||
#if !defined (EXTERNAL_CLOCK_VALUE)
|
||||
#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External audio frequency in Hz*/
|
||||
#endif /* EXTERNAL_CLOCK_VALUE */
|
||||
|
||||
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
||||
=== you can define the HSE value in your toolchain compiler preprocessor. */
|
||||
|
||||
/* ########################### System Configuration ######################### */
|
||||
/**
|
||||
* @brief This is the HAL system configuration section
|
||||
*/
|
||||
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
|
||||
#define TICK_INT_PRIORITY 15U /*!< tick interrupt priority */
|
||||
#define USE_RTOS 0U
|
||||
#define PREFETCH_ENABLE 1U
|
||||
#define INSTRUCTION_CACHE_ENABLE 1U
|
||||
#define DATA_CACHE_ENABLE 1U
|
||||
|
||||
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
|
||||
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
|
||||
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
|
||||
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
|
||||
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
|
||||
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
|
||||
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
|
||||
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
|
||||
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
|
||||
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
|
||||
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
|
||||
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
|
||||
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
|
||||
#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */
|
||||
#define USE_HAL_FMPSMBUS_REGISTER_CALLBACKS 0U /* FMPSMBUS register callback disabled */
|
||||
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
|
||||
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
|
||||
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
|
||||
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
|
||||
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
|
||||
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
|
||||
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
|
||||
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
|
||||
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
|
||||
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
|
||||
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
|
||||
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
|
||||
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
|
||||
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
|
||||
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
|
||||
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
|
||||
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
|
||||
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
|
||||
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
|
||||
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
|
||||
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
|
||||
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
|
||||
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
|
||||
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
|
||||
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* HAL drivers code
|
||||
*/
|
||||
/* #define USE_FULL_ASSERT 1U */
|
||||
|
||||
/* ################## Ethernet peripheral configuration ##################### */
|
||||
|
||||
/* Section 1 : Ethernet peripheral configuration */
|
||||
|
||||
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
|
||||
#define MAC_ADDR0 2U
|
||||
#define MAC_ADDR1 0U
|
||||
#define MAC_ADDR2 0U
|
||||
#define MAC_ADDR3 0U
|
||||
#define MAC_ADDR4 0U
|
||||
#define MAC_ADDR5 0U
|
||||
|
||||
/* Definition of the Ethernet driver buffers size and count */
|
||||
#define ETH_RX_BUF_SIZE /* buffer size for receive */
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
|
||||
#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
|
||||
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
|
||||
|
||||
/* Section 2: PHY configuration section */
|
||||
|
||||
/* DP83848_PHY_ADDRESS Address*/
|
||||
#define DP83848_PHY_ADDRESS 0x01U
|
||||
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
|
||||
#define PHY_RESET_DELAY 0x000000FFU
|
||||
/* PHY Configuration delay */
|
||||
#define PHY_CONFIG_DELAY 0x00000FFFU
|
||||
|
||||
#define PHY_READ_TO 0x0000FFFFU
|
||||
#define PHY_WRITE_TO 0x0000FFFFU
|
||||
|
||||
/* Section 3: Common PHY Registers */
|
||||
|
||||
#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */
|
||||
#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
|
||||
|
||||
#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */
|
||||
#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */
|
||||
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */
|
||||
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */
|
||||
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */
|
||||
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */
|
||||
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */
|
||||
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */
|
||||
#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */
|
||||
#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */
|
||||
|
||||
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */
|
||||
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
|
||||
#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */
|
||||
|
||||
/* Section 4: Extended PHY Registers */
|
||||
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
|
||||
|
||||
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
|
||||
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
|
||||
|
||||
/* ################## SPI peripheral configuration ########################## */
|
||||
|
||||
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
|
||||
* Activated: CRC code is present inside driver
|
||||
* Deactivated: CRC code cleaned from driver
|
||||
*/
|
||||
|
||||
#define USE_SPI_CRC 0U
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Include module's header file
|
||||
*/
|
||||
|
||||
#ifdef HAL_RCC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rcc.h"
|
||||
#endif /* HAL_RCC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_GPIO_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_gpio.h"
|
||||
#endif /* HAL_GPIO_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_EXTI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_exti.h"
|
||||
#endif /* HAL_EXTI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma.h"
|
||||
#endif /* HAL_DMA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CORTEX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cortex.h"
|
||||
#endif /* HAL_CORTEX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ADC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_adc.h"
|
||||
#endif /* HAL_ADC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_can.h"
|
||||
#endif /* HAL_CAN_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_can_legacy.h"
|
||||
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_crc.h"
|
||||
#endif /* HAL_CRC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRYP_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cryp.h"
|
||||
#endif /* HAL_CRYP_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA2D_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma2d.h"
|
||||
#endif /* HAL_DMA2D_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DAC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dac.h"
|
||||
#endif /* HAL_DAC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DCMI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dcmi.h"
|
||||
#endif /* HAL_DCMI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ETH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_eth.h"
|
||||
#endif /* HAL_ETH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FLASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_flash.h"
|
||||
#endif /* HAL_FLASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sram.h"
|
||||
#endif /* HAL_SRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NOR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nor.h"
|
||||
#endif /* HAL_NOR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NAND_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nand.h"
|
||||
#endif /* HAL_NAND_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pccard.h"
|
||||
#endif /* HAL_PCCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SDRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sdram.h"
|
||||
#endif /* HAL_SDRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hash.h"
|
||||
#endif /* HAL_HASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2c.h"
|
||||
#endif /* HAL_I2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMBUS_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_smbus.h"
|
||||
#endif /* HAL_SMBUS_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2S_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2s.h"
|
||||
#endif /* HAL_I2S_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_iwdg.h"
|
||||
#endif /* HAL_IWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LTDC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_ltdc.h"
|
||||
#endif /* HAL_LTDC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PWR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pwr.h"
|
||||
#endif /* HAL_PWR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RNG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rng.h"
|
||||
#endif /* HAL_RNG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RTC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rtc.h"
|
||||
#endif /* HAL_RTC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SAI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sai.h"
|
||||
#endif /* HAL_SAI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sd.h"
|
||||
#endif /* HAL_SD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spi.h"
|
||||
#endif /* HAL_SPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_tim.h"
|
||||
#endif /* HAL_TIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_uart.h"
|
||||
#endif /* HAL_UART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_USART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_usart.h"
|
||||
#endif /* HAL_USART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IRDA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_irda.h"
|
||||
#endif /* HAL_IRDA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMARTCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_smartcard.h"
|
||||
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_WWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_wwdg.h"
|
||||
#endif /* HAL_WWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pcd.h"
|
||||
#endif /* HAL_PCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hcd.h"
|
||||
#endif /* HAL_HCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DSI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dsi.h"
|
||||
#endif /* HAL_DSI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_QSPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_qspi.h"
|
||||
#endif /* HAL_QSPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CEC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cec.h"
|
||||
#endif /* HAL_CEC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FMPI2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_fmpi2c.h"
|
||||
#endif /* HAL_FMPI2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FMPSMBUS_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_fmpsmbus.h"
|
||||
#endif /* HAL_FMPSMBUS_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPDIFRX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spdifrx.h"
|
||||
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DFSDM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dfsdm.h"
|
||||
#endif /* HAL_DFSDM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LPTIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_lptim.h"
|
||||
#endif /* HAL_LPTIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_MMC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_mmc.h"
|
||||
#endif /* HAL_MMC_MODULE_ENABLED */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr If expr is false, it calls assert_failed function
|
||||
* which reports the name of the source file and the source
|
||||
* line number of the call that failed.
|
||||
* If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(uint8_t* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_HAL_CONF_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_it.h
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2022 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_IT_H
|
||||
#define __STM32F4xx_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ET */
|
||||
|
||||
/* USER CODE END ET */
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EC */
|
||||
|
||||
/* USER CODE END EC */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EM */
|
||||
|
||||
/* USER CODE END EM */
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void MemManage_Handler(void);
|
||||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
/* USER CODE END EFP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_IT_H */
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
#ifndef __TRANSFER_H__
|
||||
#define __TRANSFER_H__
|
||||
|
||||
#include "bsp_common.h"
|
||||
|
||||
/* 是否使能断帧检测 */
|
||||
#define DT_ENABLE_BROKEN_FRAME_DETECT 0
|
||||
|
||||
#define BROKEN_FRAME_INTERVAL_TIME 100 /* 断帧间隔时间判断,单位 ms */
|
||||
|
||||
typedef enum {
|
||||
X_RESULT_RECV_FRAME = 0x00, /* 收到了一帧数据 */
|
||||
X_RESULT_NO_DATA = 0x01, /* 未收到数据 */
|
||||
X_RESULT_JUST_RECV = 0x02, /* 刚收到一帧数据(可能是断帧) */
|
||||
X_RESULT_WAIT_DECTECT = 0x03 /* 等待断帧判断 */
|
||||
} exRESULT;
|
||||
|
||||
struct transfer_t {
|
||||
uint8_t if_id;
|
||||
|
||||
uint8_t *rx_buff;
|
||||
uint16_t *rx_len;
|
||||
uint32_t rx_buff_size;
|
||||
};
|
||||
|
||||
|
||||
extern void DT_Init (struct transfer_t *xfer, uint8_t if_id, uint8_t *buff, uint16_t *len, uint32_t buff_size);
|
||||
extern void DT_Send (struct transfer_t *xfer, uint8_t *data, uint32_t len);
|
||||
extern exRESULT DT_PollingReceive (struct transfer_t *xfer);
|
||||
|
||||
|
||||
|
||||
#endif /* __TRANSFER_H__ */
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern int hex_printf (const uint8_t *buff, int count);
|
||||
|
||||
extern uint16_t crc16_xmodem (uint8_t *data, uint16_t length);
|
||||
|
||||
extern uint32_t crc32_step (uint32_t in_crc, const void *buf, uint32_t size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
#ifndef __YMODEM_H__
|
||||
#define __YMODEM_H__
|
||||
|
||||
#include "bsp_common.h"
|
||||
#include "firmware.h"
|
||||
|
||||
/* YModem 协议 */
|
||||
#define YMODEM_SOH 0x01
|
||||
#define YMODEM_STX 0x02
|
||||
#define YMODEM_EOT 0x04
|
||||
#define YMODEM_ACK 0x06
|
||||
#define YMODEM_NAK 0x15
|
||||
#define YMODEM_CAN 0x18 // graceful abort: two CAN (0x18)
|
||||
|
||||
#define YMODEM_FRAME_FIXED_LEN (5)
|
||||
#define YMODEM_SOH_DATA_LEN (128)
|
||||
#define YMODEM_STX_DATA_LEN (1024)
|
||||
#define YMODEM_SOH_FRAME_LEN (YMODEM_FRAME_FIXED_LEN + YMODEM_SOH_DATA_LEN)
|
||||
#define YMODEM_STX_FRAME_LEN (YMODEM_FRAME_FIXED_LEN + YMODEM_STX_DATA_LEN)
|
||||
#define YMODEM_C 'C'
|
||||
|
||||
/* 协议包数据最大长度定义,因以下两个宏定义在 app.c 中也使用,因此不建议修改宏定义名称,更改宏定义内容即可 */
|
||||
#define YM_BODY_SIZE_MAX YMODEM_STX_DATA_LEN
|
||||
#define YM_MSG_SIZE_MAX YMODEM_STX_FRAME_LEN
|
||||
|
||||
typedef enum {
|
||||
YMODEM_FLOW_NONE = 0x00,
|
||||
YMODEM_FLOW_START,
|
||||
YMODEM_FLOW_FIRST_EOT,
|
||||
YMODEM_FLOW_SECOND_EOT,
|
||||
YMODEM_FLOW_ASK,
|
||||
YMODEM_FLOW_SUCCESS,
|
||||
YMODEM_FLOW_FAILED,
|
||||
YMODEM_FLOW_CANCEL
|
||||
|
||||
} eYmFLOW;
|
||||
|
||||
#pragma pack(1)
|
||||
union message_raw_t {
|
||||
uint8_t raw_data[YM_MSG_SIZE_MAX]; /* 数据缓存池,接收到来自上位机的原始数据 */
|
||||
|
||||
struct {
|
||||
uint8_t header; /* start of header */
|
||||
uint8_t pkt_num; /* packet number */
|
||||
uint8_t not_pkt_num; /* the invert of packet number's bit */
|
||||
uint8_t data[]; /* packet data */
|
||||
} pkg;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
/* 协议包含的指令 */
|
||||
typedef enum {
|
||||
YM_CMD_NONE = 0x00,
|
||||
YM_CMD_SOH = YMODEM_SOH,
|
||||
YM_CMD_STX = YMODEM_STX,
|
||||
YM_CMD_EOT = YMODEM_EOT,
|
||||
YM_CMD_CAN = YMODEM_CAN
|
||||
} eYmCMD;
|
||||
|
||||
/* 协议指令的执行结果 */
|
||||
typedef enum {
|
||||
YM_RESULT_OK = 0x00, /* 执行成功 */
|
||||
YM_RESULT_PROCESS = 0x01, /* 执行中 */
|
||||
YM_RESULT_FAILED = 0x02, /* 执行失败,重试 */
|
||||
YM_RESULT_CANCEL = 0x03 /* 执行失败,取消传输 */
|
||||
} eRESULT;
|
||||
|
||||
/* 对协议析构层的配置选项 */
|
||||
typedef enum {
|
||||
YM_MODE_NONE = 0x00,
|
||||
YM_MODE_RESET = 0x01,
|
||||
YM_MODE_RECV = 0x02
|
||||
} eYmMODE;
|
||||
|
||||
/* 需要打包发送至上位机的数据 */
|
||||
struct tx_raw_t {
|
||||
uint8_t response;
|
||||
};
|
||||
|
||||
|
||||
/* typedef of function */
|
||||
typedef void (*ymSend)(uint8_t *data, uint16_t len, uint32_t timeout);
|
||||
typedef void (*ymPrepareCallback)(eYmCMD cmd, uint8_t *data, uint16_t data_len);
|
||||
typedef void (*ymReplyCallback)(eYmCMD cmd, eRESULT *result, uint8_t *data, uint16_t *data_len);
|
||||
|
||||
|
||||
/* 函数定义 */
|
||||
extern void ymodem_init (ymSend Send,
|
||||
ymPrepareCallback PrepareCallback,
|
||||
ymReplyCallback Set_ResponseInfo);
|
||||
|
||||
extern eErrCode ymodemHandler (uint8_t *data, uint16_t len);
|
||||
extern void ymodemConfig (eYmMODE para, void *value);
|
||||
|
||||
#endif /* __YMODEM_H__ */
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "app_config.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
UART_HandleTypeDef huart1;
|
||||
UART_HandleTypeDef huart2;
|
||||
DMA_HandleTypeDef hdma_usart1_rx;
|
||||
DMA_HandleTypeDef hdma_usart2_rx;
|
||||
|
||||
|
||||
extern void System_Init(void);
|
||||
extern void APP_Init(void);
|
||||
extern void APP_Running(void);
|
||||
|
||||
|
||||
#if defined(STM32F405xx)
|
||||
|
||||
void SystemClock_Config (void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLM = 4;
|
||||
RCC_OscInitStruct.PLL.PLLN = 168;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLQ = 4;
|
||||
HAL_RCC_OscConfig(&RCC_OscInitStruct);
|
||||
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
||||
|
||||
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
|
||||
}
|
||||
|
||||
#elif defined(STM32F411xE)||defined(STM32F401xC)
|
||||
|
||||
void SystemClock_Config (void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
|
||||
RCC_OscInitStruct.PLL.PLLM = 8;
|
||||
RCC_OscInitStruct.PLL.PLLN = 100;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLQ = 4;
|
||||
HAL_RCC_OscConfig(&RCC_OscInitStruct);
|
||||
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void MX_GPIO_Init (void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
|
||||
#if (ENABLE_FACTORY_FIRMWARE_BUTTON)
|
||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||
|
||||
GPIO_InitStruct.Pin = KEY0_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(KEY0_GPIO_Port, &GPIO_InitStruct);
|
||||
#endif
|
||||
|
||||
GPIO_InitStruct.Pin = LED0_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(LED0_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
|
||||
static void MX_DMA_Init(void)
|
||||
{
|
||||
|
||||
/* DMA controller clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
|
||||
/* DMA interrupt init */
|
||||
// usart1 rx
|
||||
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
|
||||
// usart2 rx
|
||||
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
}
|
||||
|
||||
void MX_DMA_DeInit (void)
|
||||
{
|
||||
HAL_DMA_DeInit(&hdma_usart1_rx);
|
||||
HAL_DMA_DeInit(&hdma_usart2_rx);
|
||||
}
|
||||
|
||||
static void MX_USART_Init (void)
|
||||
{
|
||||
huart1.Instance = USART1;
|
||||
huart1.Init.BaudRate = 115200;
|
||||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart1.Init.StopBits = UART_STOPBITS_1;
|
||||
huart1.Init.Parity = UART_PARITY_NONE;
|
||||
huart1.Init.Mode = UART_MODE_TX_RX;
|
||||
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
HAL_UART_Init(&huart1);
|
||||
|
||||
huart2.Instance = USART2;
|
||||
huart2.Init.BaudRate = 115200;
|
||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||
huart2.Init.Parity = UART_PARITY_NONE;
|
||||
huart2.Init.Mode = UART_MODE_TX_RX;
|
||||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
HAL_UART_Init(&huart2);
|
||||
}
|
||||
|
||||
void MX_USART_DeInit (void)
|
||||
{
|
||||
HAL_UART_DeInit(&huart1);
|
||||
HAL_UART_DeInit(&huart2);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
HAL_Init();
|
||||
SystemClock_Config();
|
||||
|
||||
System_Init();
|
||||
|
||||
MX_GPIO_Init();
|
||||
MX_DMA_Init();
|
||||
MX_USART_Init();
|
||||
|
||||
printf("\r\n\r\n========================================\r\n");
|
||||
printf("\t%s boot V%d.%d.%d\r\n", NAME_CHIP,
|
||||
VERSION_MAIN, VERSION_SUB, VERSION_FIX);
|
||||
printf("\tbuilt @ %s\r\n", BUILD_TIMESTAMP);
|
||||
printf("Chip UID: %08X - %08X - %08X\r\n",
|
||||
HAL_GetUIDw0(), HAL_GetUIDw1(), HAL_GetUIDw2());
|
||||
printf("========================================\r\n");
|
||||
|
||||
APP_Init();
|
||||
|
||||
while (1) {
|
||||
APP_Running();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fputc(int ch, FILE *f)
|
||||
{
|
||||
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xffff);
|
||||
return ch;
|
||||
}
|
||||
|
||||
int fgetc(FILE * f)
|
||||
{
|
||||
uint8_t ch = 0;
|
||||
HAL_UART_Receive(&huart2,&ch, 1, 0xffff);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "main.h"
|
||||
|
||||
extern DMA_HandleTypeDef hdma_usart1_rx;
|
||||
extern DMA_HandleTypeDef hdma_usart2_rx;
|
||||
|
||||
void HAL_MspInit (void)
|
||||
{
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
}
|
||||
|
||||
void HAL_UART_MspInit (UART_HandleTypeDef* huart)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
if (huart->Instance == USART1) {
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
|
||||
// PA9 ------> USART1_TX
|
||||
// PA10 ------> USART1_RX
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
hdma_usart1_rx.Instance = DMA2_Stream2;
|
||||
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
|
||||
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
HAL_DMA_Init(&hdma_usart1_rx);
|
||||
|
||||
__HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);
|
||||
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(USART1_IRQn);
|
||||
} else if (huart->Instance == USART2) {
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
|
||||
// PA2 ------> USART2_TX
|
||||
// PA3 ------> USART2_RX
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
hdma_usart2_rx.Instance = DMA1_Stream5;
|
||||
hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
|
||||
hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
HAL_DMA_Init(&hdma_usart2_rx);
|
||||
|
||||
__HAL_LINKDMA(huart, hdmarx, hdma_usart2_rx);
|
||||
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_UART_MspDeInit (UART_HandleTypeDef* huart)
|
||||
{
|
||||
if (huart->Instance == USART1) {
|
||||
__HAL_RCC_USART1_CLK_DISABLE();
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
|
||||
HAL_DMA_DeInit(huart->hdmarx);
|
||||
HAL_NVIC_DisableIRQ(USART1_IRQn);
|
||||
} else if (huart->Instance == USART2) {
|
||||
__HAL_RCC_USART2_CLK_DISABLE();
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
|
||||
HAL_DMA_DeInit(huart->hdmarx);
|
||||
HAL_NVIC_DisableIRQ(USART2_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2022 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "stm32f4xx_it.h"
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN TD */
|
||||
|
||||
/* USER CODE END TD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN EV */
|
||||
|
||||
/* USER CODE END EV */
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M4 Processor Interruption and Exception Handlers */
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @brief This function handles Non maskable interrupt.
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard fault interrupt.
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END HardFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Memory management fault.
|
||||
*/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
||||
|
||||
/* USER CODE END MemoryManagement_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
|
||||
/* USER CODE END W1_MemoryManagement_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pre-fetch fault, memory access fault.
|
||||
*/
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN BusFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END BusFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
|
||||
/* USER CODE END W1_BusFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Undefined instruction or illegal state.
|
||||
*/
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UsageFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END UsageFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
|
||||
/* USER CODE END W1_UsageFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System service call via SWI instruction.
|
||||
*/
|
||||
void SVC_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SVCall_IRQn 0 */
|
||||
|
||||
/* USER CODE END SVCall_IRQn 0 */
|
||||
/* USER CODE BEGIN SVCall_IRQn 1 */
|
||||
|
||||
/* USER CODE END SVCall_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Debug monitor.
|
||||
*/
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
|
||||
|
||||
/* USER CODE END DebugMonitor_IRQn 0 */
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
|
||||
|
||||
/* USER CODE END DebugMonitor_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pendable request for system service.
|
||||
*/
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN PendSV_IRQn 0 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 0 */
|
||||
/* USER CODE BEGIN PendSV_IRQn 1 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System tick timer.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
extern void drv_timer_handler (uint8_t ms);
|
||||
drv_timer_handler(1);
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
HAL_IncTick();
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F4xx Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/* For the available peripheral interrupt handler names, */
|
||||
/* please refer to the startup file (startup_stm32f4xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f4xx.c
|
||||
* @author MCD Application Team
|
||||
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f4xx.s" file.
|
||||
*
|
||||
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
|
||||
* by the user application to setup the SysTick
|
||||
* timer or configure other parameters.
|
||||
*
|
||||
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
|
||||
* be called whenever the core clock is changed
|
||||
* during program execution.
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f4xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#include "stm32f4xx.h"
|
||||
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
|
||||
/************************* Miscellaneous Configuration ************************/
|
||||
/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* #define DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
|
||||
STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* #define DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\
|
||||
STM32F479xx */
|
||||
|
||||
/* Note: Following vector table addresses must be defined in line with linker
|
||||
configuration. */
|
||||
/*!< Uncomment the following line if you need to relocate the vector table
|
||||
anywhere in Flash or Sram, else the vector table is kept at the automatic
|
||||
remap of boot address selected */
|
||||
/* #define USER_VECT_TAB_ADDRESS */
|
||||
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
/*!< Uncomment the following line if you need to relocate your vector Table
|
||||
in Sram else user remap will be done in Flash. */
|
||||
/* #define VECT_TAB_SRAM */
|
||||
#if defined(VECT_TAB_SRAM)
|
||||
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#else
|
||||
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#endif /* VECT_TAB_SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
/* This variable is updated in three ways:
|
||||
1) by calling CMSIS function SystemCoreClockUpdate()
|
||||
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
|
||||
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
|
||||
Note: If you use this function to configure the system clock; then there
|
||||
is no need to call the 2 first functions listed above, since SystemCoreClock
|
||||
variable is updated automatically.
|
||||
*/
|
||||
uint32_t SystemCoreClock = 16000000;
|
||||
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system
|
||||
* Initialize the FPU setting, vector table location and External memory
|
||||
* configuration.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* FPU settings ------------------------------------------------------------*/
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
||||
#endif
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
SystemInit_ExtMemCtl();
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/* Configure the Vector Table location -------------------------------------*/
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
* The SystemCoreClock variable contains the core clock (HCLK), it can
|
||||
* be used by the user application to setup the SysTick timer or configure
|
||||
* other parameters.
|
||||
*
|
||||
* @note Each time the core clock (HCLK) changes, this function must be called
|
||||
* to update SystemCoreClock variable value. Otherwise, any configuration
|
||||
* based on this variable will be incorrect.
|
||||
*
|
||||
* @note - The system frequency computed by this function is not the real
|
||||
* frequency in the chip. It is calculated based on the predefined
|
||||
* constant and the selected clock source:
|
||||
*
|
||||
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
|
||||
*
|
||||
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
*
|
||||
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
|
||||
*
|
||||
* (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
|
||||
* 16 MHz) but the real value may vary depending on the variations
|
||||
* in voltage and temperature.
|
||||
*
|
||||
* (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
|
||||
* depends on the application requirements), user has to ensure that HSE_VALUE
|
||||
* is same as the real frequency of the crystal used. Otherwise, this function
|
||||
* may have wrong result.
|
||||
*
|
||||
* - The result of this function could be not correct when using fractional
|
||||
* value for HSE crystal.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
|
||||
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case 0x00: /* HSI used as system clock source */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case 0x04: /* HSE used as system clock source */
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case 0x08: /* PLL used as system clock source */
|
||||
|
||||
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
|
||||
SYSCLK = PLL_VCO / PLL_P
|
||||
*/
|
||||
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
|
||||
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
|
||||
|
||||
if (pllsource != 0)
|
||||
{
|
||||
/* HSE used as PLL clock source */
|
||||
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* HSI used as PLL clock source */
|
||||
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
|
||||
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
|
||||
SystemCoreClock = pllvco/pllp;
|
||||
break;
|
||||
default:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
/* Compute HCLK frequency --------------------------------------------------*/
|
||||
/* Get HCLK prescaler */
|
||||
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
|
||||
/* HCLK frequency */
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM)
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
#if defined (DATA_IN_ExtSDRAM)
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x0000007D;
|
||||
#else
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
#endif /* STM32F446xx */
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Connect PAx pins to FMC Alternate function */
|
||||
GPIOA->AFR[0] |= 0xC0000000;
|
||||
GPIOA->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOA->MODER |= 0x00008000;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOA->OSPEEDR |= 0x00008000;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOA->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOA->PUPDR |= 0x00000000;
|
||||
|
||||
/* Connect PCx pins to FMC Alternate function */
|
||||
GPIOC->AFR[0] |= 0x00CC0000;
|
||||
GPIOC->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOC->MODER |= 0x00000A00;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOC->OSPEEDR |= 0x00000A00;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOC->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOC->PUPDR |= 0x00000000;
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x000000CC;
|
||||
GPIOD->AFR[1] = 0xCC000CCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xA02A000A;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOD->OSPEEDR = 0xA02A000A;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00000CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA800A;
|
||||
/* Configure PEx pins speed to 50 MHz */
|
||||
GPIOE->OSPEEDR = 0xAAAA800A;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
/* Configure and enable SDRAM bank1 */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCR[0] = 0x00001954;
|
||||
#else
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
#endif /* STM32F446xx */
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x000000F3;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
#endif /* STM32F446xx */
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x00044014;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
#endif /* STM32F446xx */
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
|
||||
#else
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
#endif /* DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
|
||||
#if defined(DATA_IN_ExtSRAM)
|
||||
/*-- GPIOs Configuration -----------------------------------------------------*/
|
||||
/* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
|
||||
RCC->AHB1ENR |= 0x00000078;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0x00CCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCC0000;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA000AAA;
|
||||
/* Configure PFx pins speed to 100 MHz */
|
||||
GPIOF->OSPEEDR = 0xFF000FFF;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0x00CCCCCC;
|
||||
GPIOG->AFR[1] = 0x000000C0;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0x00085AAA;
|
||||
/* Configure PGx pins speed to 100 MHz */
|
||||
GPIOG->OSPEEDR = 0x000CAFFF;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC/FSMC Configuration --------------------------------------------------*/
|
||||
/* Enable the FMC/FSMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
|
||||
|| defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FSMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FSMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\
|
||||
STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Reference in New Issue
Block a user