prj to mdks

This commit is contained in:
hwq
2025-09-17 09:11:22 +08:00
parent ea8dcada90
commit 31a048e428
44 changed files with 268 additions and 2966 deletions
+569
View File
@@ -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
+862
View File
@@ -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
+100
View File
@@ -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
}
+104
View File
@@ -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;
}
+336
View File
@@ -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);
}
+90
View File
@@ -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_
+91
View File
@@ -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
+230
View File
@@ -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
+72
View File
@@ -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
+36
View File
@@ -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 */
+36
View File
@@ -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__ */
+13
View File
@@ -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
+99
View File
@@ -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__ */
+202
View File
@@ -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;
}
+95
View File
@@ -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);
}
}
+204
View File
@@ -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 */
+747
View File
@@ -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 */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/