git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13269 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
e85ee4b43d
commit
575eaf312d
|
@ -1,11 +0,0 @@
|
|||
PLATFORMSRC +=$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c
|
||||
|
||||
|
||||
|
||||
PLATFORMINC +=$(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1
|
||||
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "sama_crypto_lld.h"
|
||||
|
||||
void sama_aes_lld_write_key(const uint32_t * key, const uint32_t * vectors,
|
||||
uint32_t len) {
|
||||
|
||||
AES->AES_KEYWR[0] = key[0];
|
||||
AES->AES_KEYWR[1] = key[1];
|
||||
AES->AES_KEYWR[2] = key[2];
|
||||
AES->AES_KEYWR[3] = key[3];
|
||||
|
||||
if (len >= 24) {
|
||||
AES->AES_KEYWR[4] = key[4];
|
||||
AES->AES_KEYWR[5] = key[5];
|
||||
}
|
||||
|
||||
else {
|
||||
AES->AES_KEYWR[4] = 0;
|
||||
AES->AES_KEYWR[5] = 0;
|
||||
AES->AES_KEYWR[6] = 0;
|
||||
AES->AES_KEYWR[7] = 0;
|
||||
}
|
||||
|
||||
if (len == 32) {
|
||||
AES->AES_KEYWR[6] = key[6];
|
||||
AES->AES_KEYWR[7] = key[7];
|
||||
}
|
||||
|
||||
if (vectors != NULL) {
|
||||
AES->AES_IVR[0] = vectors[0];
|
||||
AES->AES_IVR[1] = vectors[1];
|
||||
AES->AES_IVR[2] = vectors[2];
|
||||
AES->AES_IVR[3] = vectors[3];
|
||||
}
|
||||
|
||||
else {
|
||||
AES->AES_IVR[0] = 0;
|
||||
AES->AES_IVR[1] = 0;
|
||||
AES->AES_IVR[2] = 0;
|
||||
AES->AES_IVR[3] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cryerror_t sama_aes_lld_set_key_size(size_t size) {
|
||||
|
||||
uint32_t key_size = AES_MR_KEYSIZE_AES128;
|
||||
|
||||
if (size == 16)
|
||||
key_size = AES_MR_KEYSIZE_AES128;
|
||||
else if (size == 24)
|
||||
key_size = AES_MR_KEYSIZE_AES192;
|
||||
else if (size == 32)
|
||||
key_size = AES_MR_KEYSIZE_AES256;
|
||||
else
|
||||
return CRY_ERR_INV_KEY_SIZE;
|
||||
//set key size
|
||||
AES->AES_MR |= (( AES_MR_KEYSIZE_Msk & (key_size)) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
return CRY_NOERROR;
|
||||
}
|
||||
|
||||
void sama_aes_lld_set_input(uint32_t* data) {
|
||||
uint8_t i;
|
||||
uint8_t size = 4;
|
||||
|
||||
if ((AES->AES_MR & AES_MR_OPMOD_Msk) == AES_MR_OPMOD_CFB) {
|
||||
if ((AES->AES_MR & AES_MR_CFBS_Msk) == AES_MR_CFBS_SIZE_128BIT)
|
||||
size = 4;
|
||||
else if ((AES->AES_MR & AES_MR_CFBS_Msk) == AES_MR_CFBS_SIZE_64BIT)
|
||||
size = 2;
|
||||
else
|
||||
size = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
AES->AES_IDATAR[i] = data[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sama_aes_lld_get_output(uint32_t* data) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
data[i] = (AES->AES_ODATAR[i]);
|
||||
}
|
||||
}
|
||||
|
||||
cryerror_t sama_aes_lld_process_polling(CRYDriver *cryp, aesparams *params,
|
||||
const uint8_t *in, uint8_t *out, size_t indata_len) {
|
||||
uint32_t i;
|
||||
cryerror_t ret;
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
//AES soft reset
|
||||
AES->AES_CR = AES_CR_SWRST;
|
||||
|
||||
//AES set op mode
|
||||
AES->AES_MR |= ((AES_MR_OPMOD_Msk & (params->mode)) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
//AES set key size
|
||||
ret = sama_aes_lld_set_key_size(cryp->key0_size);
|
||||
|
||||
if (ret == CRY_NOERROR) {
|
||||
|
||||
AES->AES_MR |= (AES_MR_CFBS(cryp->config->cfbs) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
|
||||
|
||||
sama_aes_lld_write_key(cryp->key0_buffer,( const uint32_t *) params->iv, cryp->key0_size);
|
||||
|
||||
|
||||
|
||||
if (params->encrypt)
|
||||
AES->AES_MR |= AES_MR_CIPHER;
|
||||
else
|
||||
AES->AES_MR &= ~AES_MR_CIPHER;
|
||||
|
||||
AES->AES_MR |= (((AES_MR_SMOD_Msk & (AES_MR_SMOD_MANUAL_START))) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
//Enable aes interrupt
|
||||
AES->AES_IER = AES_IER_DATRDY;
|
||||
|
||||
for (i = 0; i < indata_len; i += params->block_size) {
|
||||
|
||||
sama_aes_lld_set_input((uint32_t *) ((in) + i));
|
||||
|
||||
AES->AES_CR = AES_CR_START;
|
||||
|
||||
while ((AES->AES_ISR & AES_ISR_DATRDY) != AES_ISR_DATRDY);
|
||||
|
||||
sama_aes_lld_get_output((uint32_t *) ((out) + i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return CRY_NOERROR;
|
||||
|
||||
}
|
||||
|
||||
cryerror_t sama_aes_lld_process_dma(CRYDriver *cryp, aesparams *params,
|
||||
const uint8_t *in, uint8_t *out, size_t indata_len) {
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
cryerror_t ret;
|
||||
|
||||
osalDbgAssert(cryp->thread == NULL, "already waiting");
|
||||
osalDbgAssert(!((uint32_t) in & (L1_CACHE_BYTES - 1)), "in address not cache aligned");
|
||||
osalDbgAssert(!((uint32_t) out & (L1_CACHE_BYTES - 1)), "out address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(indata_len & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
* TODO: remove when size assert works
|
||||
*/
|
||||
if (indata_len & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) out, indata_len);
|
||||
}
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
cacheCleanRegion((uint8_t *) in, indata_len);
|
||||
|
||||
cryp->out = out;
|
||||
cryp->in = in;
|
||||
cryp->len = indata_len;
|
||||
|
||||
//set chunk size
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_4;
|
||||
|
||||
if ((cryp->config->cfbs != AES_CFBS_128))
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_1;
|
||||
|
||||
//set dma width
|
||||
cryp->dmawith = DMA_DATA_WIDTH_WORD;
|
||||
|
||||
if (cryp->config->cfbs == AES_CFBS_16)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_HALF_WORD;
|
||||
if (cryp->config->cfbs == AES_CFBS_8)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_BYTE;
|
||||
|
||||
cryp->rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_PER2MEM | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_AES_RX);
|
||||
|
||||
cryp->txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_AES_TX);
|
||||
|
||||
dmaChannelSetMode(cryp->dmarx, cryp->rxdmamode);
|
||||
dmaChannelSetMode(cryp->dmatx, cryp->txdmamode);
|
||||
|
||||
// Writing channel
|
||||
dmaChannelSetSource(cryp->dmatx, in);
|
||||
dmaChannelSetDestination(cryp->dmatx, AES->AES_IDATAR);
|
||||
dmaChannelSetTransactionSize(cryp->dmatx, ( indata_len / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
|
||||
// Reading channel
|
||||
dmaChannelSetSource(cryp->dmarx, AES->AES_ODATAR);
|
||||
dmaChannelSetDestination(cryp->dmarx, out);
|
||||
dmaChannelSetTransactionSize(cryp->dmarx, ( indata_len / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
//AES soft reset
|
||||
AES->AES_CR = AES_CR_SWRST;
|
||||
|
||||
//AES set op mode
|
||||
AES->AES_MR |= ((AES_MR_OPMOD_Msk & (params->mode)) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
//AES set key size
|
||||
ret = sama_aes_lld_set_key_size(cryp->key0_size);
|
||||
|
||||
if (ret == CRY_NOERROR) {
|
||||
|
||||
AES->AES_MR |= (AES_MR_CFBS(cryp->config->cfbs) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
sama_aes_lld_write_key(cryp->key0_buffer,( const uint32_t *) params->iv, cryp->key0_size);
|
||||
|
||||
if (params->encrypt)
|
||||
AES->AES_MR |= AES_MR_CIPHER;
|
||||
else
|
||||
AES->AES_MR &= ~AES_MR_CIPHER;
|
||||
|
||||
AES->AES_MR |= (((AES_MR_SMOD_Msk & (AES_MR_SMOD_IDATAR0_START)))
|
||||
| AES_MR_CKEY_PASSWD);
|
||||
|
||||
//Enable aes interrupt
|
||||
AES->AES_IER = AES_IER_DATRDY;
|
||||
|
||||
}
|
||||
|
||||
osalSysLock();
|
||||
|
||||
dmaChannelEnable(cryp->dmarx);
|
||||
dmaChannelEnable(cryp->dmatx);
|
||||
|
||||
osalThreadSuspendS(&cryp->thread);
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
#endif //#if defined(SAMA_DMA_REQUIRED)
|
||||
return CRY_NOERROR;
|
||||
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_CRY */
|
||||
|
||||
/** @} */
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#ifndef CRYPTOLIB_LLD_SAMA_AES_H_
|
||||
#define CRYPTOLIB_LLD_SAMA_AES_H_
|
||||
|
||||
extern void sama_aes_lld_write_key(const uint32_t * key, const uint32_t * vectors,uint32_t len);
|
||||
extern cryerror_t sama_aes_lld_set_key_size(size_t size);
|
||||
extern cryerror_t sama_aes_lld_process_polling(CRYDriver *cryp,aesparams *params,const uint8_t *in,uint8_t *out,size_t indata_len);
|
||||
extern cryerror_t sama_aes_lld_process_dma(CRYDriver *cryp,aesparams *params,const uint8_t *in,uint8_t *out,size_t indata_len);
|
||||
|
||||
extern void sama_aes_lld_set_input(uint32_t* data);
|
||||
extern void sama_aes_lld_get_output(uint32_t* data);
|
||||
|
||||
|
||||
|
||||
#endif /* CRYPTOLIB_LLD_SAMA_AES_H_ */
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "sama_crypto_lld.h"
|
||||
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
static void crypto_lld_serve_read_interrupt(CRYDriver *cryp, uint32_t flags);
|
||||
static void crypto_lld_serve_write_interrupt(CRYDriver *cryp, uint32_t flags);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Wakes up the waiting thread.
|
||||
*
|
||||
* @param[in] cryp pointer to the @p CRYDRiver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define _cry_wakeup_isr(cryp) { \
|
||||
osalSysLockFromISR(); \
|
||||
osalThreadResumeI(&cryp->thread, MSG_OK); \
|
||||
osalSysUnlockFromISR(); \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Common ISR code.
|
||||
* @details This code handles the portable part of the ISR code:
|
||||
* - Callback invocation.
|
||||
* - Waiting thread wakeup, if any.
|
||||
* - Driver state transitions.
|
||||
* .
|
||||
* @note This macro is meant to be used in the low level drivers
|
||||
* implementation only.
|
||||
*
|
||||
* @param[in] cryp pointer to the @p CRYDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define _cry_isr_code(cryp) { \
|
||||
_cry_wakeup_isr(cryp); \
|
||||
}
|
||||
|
||||
void samaCryptoDriverInit(CRYDriver *cryp) {
|
||||
cryp->enabledPer = 0;
|
||||
cryp->thread = NULL;
|
||||
osalMutexObjectInit(&cryp->mutex);
|
||||
}
|
||||
|
||||
void samaCryptoDriverStart(CRYDriver *cryp) {
|
||||
|
||||
|
||||
if (cryp->config->transfer_mode == TRANSFER_DMA)
|
||||
{
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
cryp->dmarx = dmaChannelAllocate(SAMA_CRY_CRYD1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t) crypto_lld_serve_read_interrupt, (void *) cryp);
|
||||
osalDbgAssert(cryp->dmarx != NULL, "no channel allocated");
|
||||
|
||||
cryp->dmatx = dmaChannelAllocate(SAMA_CRY_CRYD1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t) crypto_lld_serve_write_interrupt, (void *) cryp);
|
||||
osalDbgAssert(cryp->dmatx != NULL, "no channel allocated");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void samaCryptoDriverStop(CRYDriver *cryp) {
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
if (cryp->config->transfer_mode == TRANSFER_DMA)
|
||||
{
|
||||
dmaChannelRelease(cryp->dmarx);
|
||||
dmaChannelRelease(cryp->dmatx);
|
||||
}
|
||||
#endif
|
||||
samaCryptoDriverDisable(cryp);
|
||||
}
|
||||
|
||||
void samaCryptoDriverDisable(CRYDriver *cryp)
|
||||
{
|
||||
if ((cryp->enabledPer & AES_PER)) {
|
||||
cryp->enabledPer &= ~AES_PER;
|
||||
pmcDisableAES();
|
||||
}
|
||||
if ((cryp->enabledPer & TDES_PER)) {
|
||||
cryp->enabledPer &= ~TDES_PER;
|
||||
pmcDisableDES();
|
||||
}
|
||||
if ((cryp->enabledPer & SHA_PER)) {
|
||||
cryp->enabledPer &= ~SHA_PER;
|
||||
pmcDisableSHA();
|
||||
}
|
||||
if ((cryp->enabledPer & TRNG_PER)) {
|
||||
cryp->enabledPer &= ~TRNG_PER;
|
||||
TRNG->TRNG_CR = TRNG_CR_KEY_PASSWD;
|
||||
pmcDisableTRNG();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
/**
|
||||
* @brief Shared end-of-rx service routine.
|
||||
*
|
||||
* @param[in] cryp pointer to the @p CRYDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*/
|
||||
static void crypto_lld_serve_read_interrupt(CRYDriver *cryp, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_CRY_DMA_ERROR_HOOK)
|
||||
if ((flags & (XDMAC_CIS_RBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_CRY_DMA_ERROR_HOOK(cryp);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
/* D-Cache L1 is enabled */
|
||||
cacheInvalidateRegion(cryp->out, cryp->len);
|
||||
|
||||
/* Stop everything.*/
|
||||
dmaChannelDisable(cryp->dmarx);
|
||||
/* Portable CRY ISR code defined in the high level driver, note, it is
|
||||
a macro.*/
|
||||
_cry_isr_code(cryp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shared end-of-tx service routine.
|
||||
*
|
||||
* @param[in] cryp pointer to the @p CRYDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*/
|
||||
static void crypto_lld_serve_write_interrupt(CRYDriver *cryp, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
|
||||
#if defined(SAMA_CRY_DMA_ERROR_HOOK)
|
||||
(void)cryp;
|
||||
if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_CRY_DMA_ERROR_HOOK(cryp);
|
||||
}
|
||||
#else
|
||||
(void)cryp;
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
dmaChannelDisable(cryp->dmatx);
|
||||
|
||||
if (cryp->rxdmamode == 0xFFFFFFFF)
|
||||
_cry_isr_code(cryp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_CRY */
|
||||
|
||||
/** @} */
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#ifndef SAMA_CRYPTO_LLD_H_
|
||||
#define SAMA_CRYPTO_LLD_H_
|
||||
|
||||
#if HAL_USE_CRY || defined(__DOXYGEN__)
|
||||
|
||||
extern void samaCryptoDriverInit(CRYDriver *cryp);
|
||||
extern void samaCryptoDriverStart(CRYDriver *cryp);
|
||||
extern void samaCryptoDriverStop(CRYDriver *cryp);
|
||||
extern void samaCryptoDriverDisable(CRYDriver *cryp);
|
||||
|
||||
|
||||
#define AES_PER 0x01
|
||||
#define TRNG_PER 0x02
|
||||
#define SHA_PER 0x04
|
||||
#define TDES_PER 0x08
|
||||
|
||||
#define DMA_DATA_WIDTH_BYTE 0
|
||||
#define DMA_DATA_WIDTH_HALF_WORD 1
|
||||
#define DMA_DATA_WIDTH_WORD 2
|
||||
#define DMA_DATA_WIDTH_DWORD 3
|
||||
|
||||
#define DMA_CHUNK_SIZE_1 0
|
||||
#define DMA_CHUNK_SIZE_2 1
|
||||
#define DMA_CHUNK_SIZE_4 2
|
||||
#define DMA_CHUNK_SIZE_8 3
|
||||
#define DMA_CHUNK_SIZE_16 4
|
||||
|
||||
#define DMA_DATA_WIDTH_TO_BYTE(w) (1 << w)
|
||||
|
||||
#ifndef SAMA_CRY_CRYD1_DMA_IRQ_PRIORITY
|
||||
#define SAMA_CRY_CRYD1_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
#ifndef SAMA_CRY_CRYD1_IRQ_PRIORITY
|
||||
#define SAMA_CRY_CRYD1_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
#ifndef SAMA_CRY_DMA_ERROR_HOOK
|
||||
#define SAMA_CRY_DMA_ERROR_HOOK(cryp) osalSysHalt("DMA failure")
|
||||
#endif
|
||||
|
||||
#ifndef SAMA_CRY_SHA_UPDATE_LEN_MAX
|
||||
#define SAMA_CRY_SHA_UPDATE_LEN_MAX 128*1024
|
||||
#endif
|
||||
|
||||
|
||||
#include "sama_aes_lld.h"
|
||||
#include "sama_tdes_lld.h"
|
||||
#include "sama_sha_lld.h"
|
||||
#include "sama_gcm_lld.h"
|
||||
|
||||
#endif /* HAL_USE_CRY */
|
||||
|
||||
#endif //SAMA_CRYPTO_LLD_H_
|
||||
|
||||
/** @} */
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#include "hal.h"
|
||||
#include <string.h>
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "sama_crypto_lld.h"
|
||||
|
||||
static void incr32(uint8_t* j0)
|
||||
{
|
||||
|
||||
uint32_t counter = j0[15] | j0[14] << 0x8 | j0[13] << 0x10 | j0[12] << 0x18;
|
||||
|
||||
counter++;
|
||||
|
||||
j0[12] = (counter>>24) & 0xFF;
|
||||
j0[13] = (counter>>16) & 0xFF;
|
||||
j0[14] = (counter>>8) & 0xFF;
|
||||
j0[15] = counter & 0xFF;
|
||||
}
|
||||
|
||||
static cryerror_t sama_gcm_lld_process_dma(CRYDriver *cryp,cgmcontext * cxt)
|
||||
{
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
|
||||
osalDbgAssert(!((uint32_t) cxt->in & (L1_CACHE_BYTES - 1)), "in address not cache aligned");
|
||||
osalDbgAssert(!((uint32_t) cxt->out & (L1_CACHE_BYTES - 1)), "out address not cache aligned");
|
||||
osalDbgAssert(cryp->thread == NULL, "already waiting");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(cxt->c_size & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
cacheCleanRegion((uint8_t *) cxt->in, cxt->c_size);
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
* TODO: remove when size assert works
|
||||
*/
|
||||
if (cxt->c_size & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) cxt->out, cxt->c_size);
|
||||
}
|
||||
|
||||
cryp->out = cxt->out;
|
||||
cryp->in = cxt->in;
|
||||
cryp->len = cxt->c_size;
|
||||
|
||||
//set chunk size
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_4;
|
||||
|
||||
if ((cryp->config->cfbs != AES_CFBS_128))
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_1;
|
||||
|
||||
//set dma width
|
||||
cryp->dmawith = DMA_DATA_WIDTH_WORD;
|
||||
|
||||
if (cryp->config->cfbs == AES_CFBS_16)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_HALF_WORD;
|
||||
if (cryp->config->cfbs == AES_CFBS_8)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_BYTE;
|
||||
|
||||
cryp->rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_PER2MEM | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_AES_RX);
|
||||
|
||||
cryp->txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_AES_TX);
|
||||
|
||||
dmaChannelSetMode(cryp->dmarx, cryp->rxdmamode);
|
||||
dmaChannelSetMode(cryp->dmatx, cryp->txdmamode);
|
||||
|
||||
// Writing channel
|
||||
dmaChannelSetSource(cryp->dmatx, cxt->in);
|
||||
dmaChannelSetDestination(cryp->dmatx, AES->AES_IDATAR);
|
||||
dmaChannelSetTransactionSize(cryp->dmatx, ( cxt->c_size / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
|
||||
// Reading channel
|
||||
dmaChannelSetSource(cryp->dmarx, AES->AES_ODATAR);
|
||||
dmaChannelSetDestination(cryp->dmarx, cxt->out);
|
||||
dmaChannelSetTransactionSize(cryp->dmarx, ( cxt->c_size / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
AES->AES_MR |= (((AES_MR_SMOD_Msk & (AES_MR_SMOD_IDATAR0_START)))
|
||||
| AES_MR_CKEY_PASSWD);
|
||||
|
||||
//Enable aes interrupt
|
||||
AES->AES_IER = AES_IER_DATRDY;
|
||||
|
||||
osalSysLock();
|
||||
|
||||
dmaChannelEnable(cryp->dmarx);
|
||||
dmaChannelEnable(cryp->dmatx);
|
||||
|
||||
osalThreadSuspendS(&cryp->thread);
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
|
||||
#endif //#if defined(SAMA_DMA_REQUIRED)
|
||||
return CRY_NOERROR;
|
||||
|
||||
}
|
||||
|
||||
cryerror_t sama_gcm_lld_process(CRYDriver *cryp,cgmcontext * cxt)
|
||||
{
|
||||
cryerror_t ret;
|
||||
uint32_t *ref32;
|
||||
uint8_t i;
|
||||
uint8_t J0[16] = { 0x00 };
|
||||
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
|
||||
//AES soft reset
|
||||
AES->AES_CR = AES_CR_SWRST;
|
||||
|
||||
//AES set op mode
|
||||
AES->AES_MR =((AES_MR_OPMOD_Msk & (AES_MR_OPMOD_GCM)) | AES_MR_GTAGEN | AES_MR_CKEY_PASSWD);
|
||||
|
||||
|
||||
//AES set key size
|
||||
ret = sama_aes_lld_set_key_size(cryp->key0_size);
|
||||
|
||||
|
||||
if (ret == CRY_NOERROR) {
|
||||
|
||||
AES->AES_MR |= ( ((AES_MR_SMOD_Msk & (AES_MR_SMOD_MANUAL_START))) | AES_MR_CKEY_PASSWD);
|
||||
|
||||
sama_aes_lld_write_key(cryp->key0_buffer,NULL, cryp->key0_size);
|
||||
|
||||
AES->AES_CR = AES_CR_START;
|
||||
|
||||
while ((AES->AES_ISR & AES_ISR_DATRDY) != AES_ISR_DATRDY);
|
||||
|
||||
//J0
|
||||
|
||||
memcpy(J0, cxt->params.iv, 16); // copy the IV to the first 12 bytes of J0
|
||||
|
||||
incr32(J0);
|
||||
|
||||
// Write incr32(J0) into IV.
|
||||
|
||||
ref32 = (uint32_t*)J0;
|
||||
AES->AES_IVR[0] = ref32[0];
|
||||
AES->AES_IVR[1] = ref32[1];
|
||||
AES->AES_IVR[2] = ref32[2];
|
||||
AES->AES_IVR[3] = ref32[3];
|
||||
|
||||
|
||||
AES->AES_AADLENR = cxt->aadsize;
|
||||
AES->AES_CLENR = cxt->c_size;
|
||||
|
||||
if (cxt->params.encrypt)
|
||||
AES->AES_MR |= AES_MR_CIPHER;
|
||||
else
|
||||
AES->AES_MR &= ~AES_MR_CIPHER;
|
||||
|
||||
AES->AES_MR |= AES_MR_GTAGEN| AES_MR_CKEY_PASSWD;
|
||||
|
||||
|
||||
for (i = 0; i < cxt->aadsize; i += cxt->params.block_size) {
|
||||
|
||||
sama_aes_lld_set_input((uint32_t *) ((cxt->aad) + i));
|
||||
|
||||
AES->AES_CR = AES_CR_START;
|
||||
|
||||
while ((AES->AES_ISR & AES_ISR_DATRDY) != AES_ISR_DATRDY);
|
||||
|
||||
}
|
||||
|
||||
if (cryp->config->transfer_mode == TRANSFER_POLLING) {
|
||||
for (i = 0; i < cxt->c_size; i += cxt->params.block_size) {
|
||||
|
||||
sama_aes_lld_set_input((uint32_t *) ((cxt->in) + i));
|
||||
|
||||
AES->AES_CR = AES_CR_START;
|
||||
|
||||
while ((AES->AES_ISR & AES_ISR_DATRDY) != AES_ISR_DATRDY);
|
||||
|
||||
sama_aes_lld_get_output((uint32_t *) ((cxt->out) + i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sama_gcm_lld_process_dma(cryp,cxt);
|
||||
}
|
||||
|
||||
while ((AES->AES_ISR & AES_ISR_TAGRDY) != AES_ISR_TAGRDY);
|
||||
|
||||
ref32 = (uint32_t*)cxt->authtag;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ref32[i] =AES->AES_TAGR[i];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#ifndef CRYPTOLIB_LLD_SAMA_GCM_H_
|
||||
#define CRYPTOLIB_LLD_SAMA_GCM_H_
|
||||
|
||||
|
||||
|
||||
cryerror_t sama_gcm_lld_process(CRYDriver *cryp,cgmcontext * cxt);
|
||||
|
||||
|
||||
|
||||
#endif /* CRYPTOLIB_LLD_SAMA_GCM_H_ */
|
|
@ -1,477 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#include "hal.h"
|
||||
#include <string.h>
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "sama_crypto_lld.h"
|
||||
|
||||
|
||||
static inline uint32_t min_u32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint32_t shaOutputSize(shadalgo_t algo);
|
||||
static uint32_t shadPaddedMessSize(uint8_t mode, uint32_t len);
|
||||
uint8_t shaBlockSize(shadalgo_t algo);
|
||||
static void loadData(const uint8_t* data, int len);
|
||||
static void readData(const uint8_t* data, int len);
|
||||
static uint32_t processBlockPolling(const uint8_t *data,uint32_t len, uint32_t block_size);
|
||||
static uint32_t processBlockDMA(CRYDriver *cryp,const uint8_t *data, uint32_t len, uint32_t block_size);
|
||||
static void update(CRYDriver *cryp,struct sha_data *shadata,const uint8_t* data, uint32_t data_size);
|
||||
|
||||
static uint32_t fillPadding(struct sha_data *shadata, uint32_t len, uint8_t* buffer,size_t buffer_size);
|
||||
|
||||
|
||||
|
||||
uint8_t shaDigestSize(shadalgo_t algo);
|
||||
|
||||
uint8_t shaDigestSize(shadalgo_t algo)
|
||||
{
|
||||
switch(algo)
|
||||
{
|
||||
case CRY_SHA_1:
|
||||
return 20;
|
||||
break;
|
||||
case CRY_SHA_224:
|
||||
return 28;
|
||||
break;
|
||||
case CRY_SHA_256:
|
||||
return 32;
|
||||
break;
|
||||
case CRY_SHA_384:
|
||||
return 48;
|
||||
break;
|
||||
case CRY_SHA_512:
|
||||
return 64;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static cryerror_t sha_finish(CRYDriver *cryp,struct sha_data *shadata,const uint8_t* buffer,uint32_t buffer_size)
|
||||
{
|
||||
|
||||
uint32_t padding_len=0;
|
||||
|
||||
|
||||
if (buffer_size < shadata->output_size)
|
||||
return CRY_ERR_INV_ALGO;
|
||||
|
||||
//pad data for the end of the buffer
|
||||
padding_len = fillPadding(shadata,shadata->processed + shadata->remaining,&shadata->sha_buffer[shadata->remaining],shadata->sha_buffer_size - shadata->remaining);
|
||||
|
||||
if (cryp->config->transfer_mode == TRANSFER_POLLING)
|
||||
processBlockPolling(shadata->sha_buffer,shadata->remaining + padding_len, shadata->block_size);
|
||||
else
|
||||
processBlockDMA(cryp,shadata->sha_buffer,shadata->remaining + padding_len, shadata->block_size);
|
||||
|
||||
readData(buffer, buffer_size);
|
||||
return CRY_NOERROR;
|
||||
|
||||
}
|
||||
|
||||
cryerror_t sama_sha_lld_update(CRYDriver *cryp, struct sha_data *sha)
|
||||
{
|
||||
uint32_t buf_in_size;
|
||||
uint8_t* p;
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
p = (uint8_t*)sha->in;
|
||||
|
||||
while (sha->indata_len) {
|
||||
buf_in_size = min_u32(sha->indata_len, SAMA_CRY_SHA_UPDATE_LEN_MAX);
|
||||
|
||||
//First block
|
||||
if (!sha->processed) {
|
||||
SHA->SHA_CR = SHA_CR_FIRST;
|
||||
}
|
||||
|
||||
update(cryp, sha, p, buf_in_size);
|
||||
|
||||
sha->indata_len -= buf_in_size;
|
||||
p += buf_in_size;
|
||||
}
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return CRY_NOERROR;
|
||||
}
|
||||
|
||||
cryerror_t sama_sha_lld_final(CRYDriver *cryp, struct sha_data *sha)
|
||||
{
|
||||
cryerror_t err = CRY_NOERROR;
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
if (!sha->processed) {
|
||||
SHA->SHA_CR = SHA_CR_FIRST;
|
||||
}
|
||||
|
||||
err = sha_finish(cryp, sha, sha->out, sha->output_size);
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cryerror_t sama_sha_lld_init(CRYDriver *cryp, struct sha_data *sha)
|
||||
{
|
||||
uint32_t algoregval;
|
||||
cryerror_t cryerr = CRY_NOERROR;
|
||||
|
||||
if (!(cryp->enabledPer & SHA_PER)) {
|
||||
cryp->enabledPer |= SHA_PER;
|
||||
pmcEnableSHA();
|
||||
}
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
|
||||
sha->processed = 0;
|
||||
sha->remaining = 0;
|
||||
sha->output_size = shaOutputSize(sha->algo);
|
||||
sha->block_size = shaBlockSize(sha->algo);
|
||||
|
||||
|
||||
if (sha->output_size == 0) {
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
return CRY_ERR_INV_ALGO;
|
||||
}
|
||||
|
||||
switch (sha->algo) {
|
||||
case CRY_SHA_1:
|
||||
algoregval = SHA_MR_ALGO_SHA1;
|
||||
break;
|
||||
case CRY_SHA_224:
|
||||
algoregval = SHA_MR_ALGO_SHA224;
|
||||
break;
|
||||
case CRY_SHA_256:
|
||||
algoregval = SHA_MR_ALGO_SHA256;
|
||||
break;
|
||||
#ifdef SHA_MR_ALGO_SHA384
|
||||
case CRY_SHA_384:
|
||||
algoregval = SHA_MR_ALGO_SHA384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef SHA_MR_ALGO_SHA512
|
||||
case CRY_SHA_512:
|
||||
algoregval = SHA_MR_ALGO_SHA512;
|
||||
break;
|
||||
#endif
|
||||
case CRY_HMACSHA_1:
|
||||
algoregval = SHA_MR_ALGO_HMAC_SHA1;
|
||||
break;
|
||||
case CRY_HMACSHA_224:
|
||||
algoregval = SHA_MR_ALGO_HMAC_SHA224;
|
||||
break;
|
||||
case CRY_HMACSHA_256:
|
||||
algoregval = SHA_MR_ALGO_HMAC_SHA256;
|
||||
break;
|
||||
case CRY_HMACSHA_384:
|
||||
algoregval = SHA_MR_ALGO_HMAC_SHA384;
|
||||
break;
|
||||
case CRY_HMACSHA_512:
|
||||
algoregval = SHA_MR_ALGO_HMAC_SHA512;
|
||||
break;
|
||||
default:
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
return CRY_ERR_INV_ALGO;
|
||||
}
|
||||
|
||||
|
||||
//soft reset
|
||||
SHA->SHA_CR = SHA_CR_SWRST;
|
||||
|
||||
|
||||
if (cryp->config->transfer_mode == TRANSFER_POLLING) {
|
||||
algoregval |= SHA_MR_SMOD_MANUAL_START;
|
||||
} else {
|
||||
algoregval |= SHA_MR_SMOD_IDATAR0_START;
|
||||
|
||||
cryp->dmawith = DMA_DATA_WIDTH_WORD;
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_16;
|
||||
|
||||
cryp->txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_SHA_TX);
|
||||
|
||||
cryp->rxdmamode = 0xFFFFFFFF;
|
||||
|
||||
dmaChannelSetMode(cryp->dmatx, cryp->txdmamode);
|
||||
}
|
||||
|
||||
//configure
|
||||
SHA->SHA_MR = algoregval | SHA_MR_PROCDLY_LONGEST;
|
||||
|
||||
//enable interrupt
|
||||
SHA->SHA_IER = SHA_IER_DATRDY;
|
||||
|
||||
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return cryerr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint32_t shaOutputSize(shadalgo_t algo)
|
||||
{
|
||||
switch (algo) {
|
||||
case CRY_SHA_1:
|
||||
case CRY_HMACSHA_1:
|
||||
return 20;
|
||||
case CRY_SHA_224:
|
||||
case CRY_HMACSHA_224:
|
||||
return 28;
|
||||
case CRY_SHA_256:
|
||||
case CRY_HMACSHA_256:
|
||||
return 32;
|
||||
case CRY_SHA_384:
|
||||
case CRY_HMACSHA_384:
|
||||
return 48;
|
||||
case CRY_SHA_512:
|
||||
case CRY_HMACSHA_512:
|
||||
return 64;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t shadPaddedMessSize(uint8_t mode, uint32_t len)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
switch (mode) {
|
||||
case CRY_SHA_1:
|
||||
case CRY_SHA_224:
|
||||
case CRY_SHA_256:
|
||||
case CRY_HMACSHA_1:
|
||||
case CRY_HMACSHA_224:
|
||||
case CRY_HMACSHA_256:
|
||||
k = (512 + 448 - (((len * 8) % 512) + 1)) % 512;
|
||||
len += (k - 7) / 8 + 9;
|
||||
break;
|
||||
case CRY_SHA_384:
|
||||
case CRY_SHA_512:
|
||||
case CRY_HMACSHA_384:
|
||||
case CRY_HMACSHA_512:
|
||||
k = (1024 + 896 - (((len * 8) % 1024) + 1)) % 1024;
|
||||
len += (k - 7) / 8 + 17;
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t shaBlockSize(shadalgo_t algo)
|
||||
{
|
||||
|
||||
switch(algo)
|
||||
{
|
||||
case CRY_SHA_384:
|
||||
case CRY_HMACSHA_384:
|
||||
case CRY_SHA_512:
|
||||
case CRY_HMACSHA_512:
|
||||
return 128;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 64;
|
||||
}
|
||||
|
||||
|
||||
static void loadData(const uint8_t* data, int len)
|
||||
{
|
||||
int i;
|
||||
int32_t value;
|
||||
|
||||
for (i = 0; i < (len / 4) && i < 32; i++) {
|
||||
memcpy(&value, &data[i * 4], 4);
|
||||
if (i < 16)
|
||||
SHA->SHA_IDATAR[i] = value;
|
||||
else
|
||||
SHA->SHA_IODATAR[i - 16] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void readData(const uint8_t* data, int len)
|
||||
{
|
||||
int i;
|
||||
int32_t value;
|
||||
|
||||
for (i = 0; i < (len / 4) && i < 16; i++) {
|
||||
value = SHA->SHA_IODATAR[i];
|
||||
memcpy((uint8_t*)&data[i * 4], &value, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t processBlockPolling(const uint8_t *data,uint32_t len, uint32_t block_size)
|
||||
{
|
||||
uint32_t processed = 0;
|
||||
|
||||
|
||||
while ((len - processed) >= block_size) {
|
||||
|
||||
// load data in the sha input registers
|
||||
loadData(&data[processed], block_size);
|
||||
|
||||
SHA->SHA_CR = SHA_CR_START;
|
||||
|
||||
// Wait for data ready
|
||||
while ((SHA->SHA_ISR & SHA_ISR_DATRDY) == 0);
|
||||
|
||||
processed += block_size;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
static uint32_t processBlockDMA(CRYDriver *cryp, const uint8_t *data,uint32_t len, uint32_t block_size) {
|
||||
|
||||
osalDbgAssert(!((uint32_t) data & (L1_CACHE_BYTES - 1)), "data address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(block_size & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
uint32_t processed = 0;
|
||||
|
||||
cryp->out = 0;
|
||||
cryp->in = data;
|
||||
cryp->len = len;
|
||||
|
||||
cacheCleanRegion((uint8_t *) data, len);
|
||||
|
||||
while ((len - processed) >= block_size) {
|
||||
|
||||
// load data in the sha input registers
|
||||
// Writing channel
|
||||
dmaChannelSetSource(cryp->dmatx, &data[processed]);
|
||||
dmaChannelSetDestination(cryp->dmatx, SHA->SHA_IDATAR);
|
||||
dmaChannelSetTransactionSize(cryp->dmatx,
|
||||
(block_size / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
dmaChannelEnable(cryp->dmatx);
|
||||
|
||||
osalThreadSuspendS(&cryp->thread);
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
processed += block_size;
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
static void update(CRYDriver *cryp,struct sha_data *shadata,const uint8_t* data, uint32_t data_size)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t processed;
|
||||
|
||||
//check data from previous update
|
||||
if (shadata->remaining) {
|
||||
//complete previous data
|
||||
uint32_t complement = min_u32(data_size, shadata->block_size - shadata->remaining);
|
||||
memcpy(&shadata->sha_buffer[shadata->remaining], data, complement);
|
||||
shadata->remaining += complement;
|
||||
data += complement;
|
||||
data_size -= complement;
|
||||
|
||||
//if data is complete process the block
|
||||
if (shadata->remaining == shadata->block_size) {
|
||||
if (cryp->config->transfer_mode == TRANSFER_POLLING )
|
||||
processBlockPolling(shadata->sha_buffer,shadata->remaining, shadata->block_size);
|
||||
else
|
||||
processBlockDMA(cryp, shadata->sha_buffer,shadata->remaining, shadata->block_size);
|
||||
|
||||
shadata->processed += shadata->block_size;
|
||||
shadata->remaining = 0;
|
||||
} else {
|
||||
//complete processing in the next update/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Process blocks
|
||||
if (cryp->config->transfer_mode == TRANSFER_POLLING )
|
||||
processed = processBlockPolling(data,data_size, shadata->block_size);
|
||||
else
|
||||
processed = processBlockDMA(cryp, data,data_size, shadata->block_size);
|
||||
|
||||
shadata->processed += processed;
|
||||
|
||||
//check remaining data and process
|
||||
shadata->remaining = data_size - processed;
|
||||
if (shadata->remaining)
|
||||
{
|
||||
for (i=0;i<shadata->remaining;i++)
|
||||
shadata->sha_buffer[i] = data[processed+i];
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t fillPadding(struct sha_data *shadata, uint32_t len, uint8_t* buffer,size_t buffer_size)
|
||||
{
|
||||
uint32_t padding_len,k;
|
||||
|
||||
|
||||
padding_len = shadPaddedMessSize(shadata->algo, len);
|
||||
padding_len -= len;
|
||||
k = padding_len - 9;
|
||||
|
||||
osalDbgAssert( padding_len <= buffer_size,"invalid buffer size");
|
||||
|
||||
|
||||
// Append "1" bit and seven "0" bits to the end of the message
|
||||
*buffer++ = 0x80;
|
||||
// Add k "0" bits
|
||||
memset(buffer, 0, k);
|
||||
buffer += k;
|
||||
// length is at the end of message (64-bit)
|
||||
*buffer++ = 0;
|
||||
*buffer++ = 0;
|
||||
*buffer++ = 0;
|
||||
*buffer++ = (len >> 29) & 0xFF;
|
||||
*buffer++ = (len >> 21) & 0xFF;
|
||||
*buffer++ = (len >> 13) & 0xFF;
|
||||
*buffer++ = (len >> 5) & 0xFF;
|
||||
*buffer++ = (len << 3) & 0xFF;
|
||||
return padding_len;
|
||||
}
|
||||
#endif /* HAL_USE_CRY */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#ifndef CRYPTOLIB_LLD_SAMA_SHA_H_
|
||||
#define CRYPTOLIB_LLD_SAMA_SHA_H_
|
||||
|
||||
|
||||
cryerror_t sama_sha_lld_init(CRYDriver *cryp, struct sha_data *sha);
|
||||
cryerror_t sama_sha_lld_update(CRYDriver *cryp, struct sha_data *sha);
|
||||
cryerror_t sama_sha_lld_final(CRYDriver *cryp, struct sha_data *sha);
|
||||
|
||||
|
||||
|
||||
#endif /* CRYPTOLIB_LLD_SAMA_SHA_H_ */
|
|
@ -1,297 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "sama_crypto_lld.h"
|
||||
#include "sama_tdes_lld.h"
|
||||
|
||||
enum tdesd_key_mode_t {
|
||||
TDES_KEY_THREE = 0, TDES_KEY_TWO
|
||||
};
|
||||
|
||||
void tdes_set_input(uint32_t* data0, uint32_t* data1) {
|
||||
TDES->TDES_IDATAR[0] = *data0;
|
||||
if (data1)
|
||||
TDES->TDES_IDATAR[1] = *data1;
|
||||
}
|
||||
|
||||
void tdes_get_output(uint32_t *data0, uint32_t *data1) {
|
||||
*data0 = TDES->TDES_ODATAR[0];
|
||||
if (data1)
|
||||
*data1 = TDES->TDES_ODATAR[1];
|
||||
}
|
||||
|
||||
cryerror_t sama_tdes_lld_polling(CRYDriver *cryp, tdes_config_t *params,
|
||||
bool encrypt, const uint8_t *data, size_t data_len, uint8_t * out,
|
||||
const uint8_t *iv) {
|
||||
|
||||
uint32_t mode = 0;
|
||||
uint32_t i;
|
||||
uint8_t size = 8;
|
||||
uint32_t *vectors = (uint32_t *) iv;
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
//soft reset
|
||||
TDES->TDES_CR = TDES_CR_SWRST;
|
||||
//configure
|
||||
if (encrypt)
|
||||
mode |= TDES_MR_CIPHER_ENCRYPT;
|
||||
else
|
||||
mode |= TDES_MR_CIPHER_DECRYPT;
|
||||
|
||||
if (cryp->key0_size == 16)
|
||||
mode |= (TDES_KEY_TWO << 4);
|
||||
else
|
||||
mode |= (TDES_KEY_THREE << 4);
|
||||
|
||||
mode |= TDES_MR_TDESMOD(params->algo);
|
||||
|
||||
mode |= TDES_MR_SMOD_MANUAL_START;
|
||||
|
||||
mode |= TDES_MR_OPMOD(params->mode);
|
||||
|
||||
if (cryp->config != NULL) {
|
||||
mode |= TDES_MR_CFBS(cryp->config->cfbs);
|
||||
|
||||
if (params->mode == TDES_MODE_CFB) {
|
||||
if (cryp->config->cfbs == TDES_CFBS_32)
|
||||
size = 4;
|
||||
else if (cryp->config->cfbs == TDES_CFBS_16)
|
||||
size = 2;
|
||||
else if (cryp->config->cfbs == TDES_CFBS_8)
|
||||
size = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TDES->TDES_MR = mode;
|
||||
|
||||
//write keys
|
||||
|
||||
TDES->TDES_KEY1WR[0] = cryp->key0_buffer[0];
|
||||
TDES->TDES_KEY1WR[1] = cryp->key0_buffer[1];
|
||||
|
||||
if (cryp->key0_size > 8) {
|
||||
TDES->TDES_KEY2WR[0] = cryp->key0_buffer[2];
|
||||
TDES->TDES_KEY2WR[1] = cryp->key0_buffer[3];
|
||||
} else {
|
||||
TDES->TDES_KEY2WR[0] = 0x0;
|
||||
TDES->TDES_KEY2WR[1] = 0x0;
|
||||
}
|
||||
if (cryp->key0_size > 16) {
|
||||
TDES->TDES_KEY3WR[0] = cryp->key0_buffer[4];
|
||||
TDES->TDES_KEY3WR[1] = cryp->key0_buffer[5];
|
||||
} else {
|
||||
TDES->TDES_KEY3WR[0] = 0x0;
|
||||
TDES->TDES_KEY3WR[1] = 0x0;
|
||||
}
|
||||
/* The Initialization Vector Registers apply to all modes except ECB. */
|
||||
if (params->mode != TDES_MODE_ECB && vectors != NULL) {
|
||||
TDES->TDES_IVR[0] = vectors[0];
|
||||
TDES->TDES_IVR[1] = vectors[1];
|
||||
}
|
||||
if (params->algo == TDES_ALGO_XTEA) {
|
||||
TDES->TDES_XTEA_RNDR = TDES_XTEA_RNDR_XTEA_RNDS(32);
|
||||
}
|
||||
|
||||
//load 64 bit data size in tdes registers
|
||||
for (i = 0; i < data_len; i += size) {
|
||||
if (size == 8)
|
||||
tdes_set_input((uint32_t *) ((data) + i),
|
||||
(uint32_t *) ((data) + i + 4));
|
||||
else
|
||||
tdes_set_input((uint32_t *) ((data) + i), NULL);
|
||||
|
||||
//Start TDES
|
||||
TDES->TDES_CR = TDES_CR_START;
|
||||
|
||||
//check status
|
||||
while ((TDES->TDES_ISR & TDES_ISR_DATRDY) != TDES_ISR_DATRDY)
|
||||
;
|
||||
|
||||
if (size == 8)
|
||||
tdes_get_output((uint32_t *) ((out) + i),
|
||||
(uint32_t *) ((out) + i + 4));
|
||||
else
|
||||
tdes_get_output((uint32_t *) ((out) + i), NULL);
|
||||
}
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
|
||||
return CRY_NOERROR;
|
||||
}
|
||||
|
||||
cryerror_t sama_tdes_lld_dma(CRYDriver *cryp, tdes_config_t *params,
|
||||
bool encrypt, const uint8_t *data, size_t data_len, uint8_t * out,
|
||||
const uint8_t *iv) {
|
||||
|
||||
osalDbgAssert(!((uint32_t) data & (L1_CACHE_BYTES - 1)), "data address not cache aligned");
|
||||
osalDbgAssert(!((uint32_t) out & (L1_CACHE_BYTES - 1)), "out address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(data_len & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
* TODO: remove when size assert works
|
||||
*/
|
||||
if (data_len & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) out, data_len);
|
||||
}
|
||||
|
||||
uint32_t mode = 0;
|
||||
uint32_t *vectors = (uint32_t *) iv;
|
||||
|
||||
osalMutexLock(&cryp->mutex);
|
||||
|
||||
cacheCleanRegion((uint8_t *) data, data_len);
|
||||
|
||||
cryp->out = out;
|
||||
cryp->in = data;
|
||||
cryp->len = data_len;
|
||||
|
||||
cryp->dmachunksize = DMA_CHUNK_SIZE_1;
|
||||
|
||||
cryp->dmawith = DMA_DATA_WIDTH_WORD;
|
||||
|
||||
if ((params->mode == TDES_MODE_CFB)) {
|
||||
if (cryp->config->cfbs == TDES_CFBS_16)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_HALF_WORD;
|
||||
if (cryp->config->cfbs == TDES_CFBS_8)
|
||||
cryp->dmawith = DMA_DATA_WIDTH_BYTE;
|
||||
}
|
||||
|
||||
cryp->rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_PER2MEM | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_TDES_RX);
|
||||
|
||||
cryp->txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_CSIZE(cryp->dmachunksize) |
|
||||
XDMAC_CC_DWIDTH(cryp->dmawith) |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_TDES_TX);
|
||||
|
||||
dmaChannelSetMode(cryp->dmarx, cryp->rxdmamode);
|
||||
dmaChannelSetMode(cryp->dmatx, cryp->txdmamode);
|
||||
|
||||
// Writing channel
|
||||
dmaChannelSetSource(cryp->dmatx, data);
|
||||
dmaChannelSetDestination(cryp->dmatx, TDES->TDES_IDATAR);
|
||||
dmaChannelSetTransactionSize(cryp->dmatx,
|
||||
(data_len / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
|
||||
// Reading channel
|
||||
dmaChannelSetSource(cryp->dmarx, TDES->TDES_ODATAR);
|
||||
dmaChannelSetDestination(cryp->dmarx, out);
|
||||
dmaChannelSetTransactionSize(cryp->dmarx,
|
||||
(data_len / DMA_DATA_WIDTH_TO_BYTE(cryp->dmawith)));
|
||||
|
||||
//soft reset
|
||||
TDES->TDES_CR = TDES_CR_SWRST;
|
||||
|
||||
//configure
|
||||
if (encrypt)
|
||||
mode |= TDES_MR_CIPHER_ENCRYPT;
|
||||
else
|
||||
mode |= TDES_MR_CIPHER_DECRYPT;
|
||||
|
||||
if (cryp->key0_size == 16)
|
||||
mode |= (TDES_KEY_TWO << 4);
|
||||
else
|
||||
mode |= (TDES_KEY_THREE << 4);
|
||||
|
||||
mode |= TDES_MR_TDESMOD(params->algo);
|
||||
|
||||
mode |= TDES_MR_SMOD_IDATAR0_START;
|
||||
|
||||
mode |= TDES_MR_OPMOD(params->mode);
|
||||
|
||||
if (cryp->config != NULL) {
|
||||
mode |= TDES_MR_CFBS(cryp->config->cfbs);
|
||||
}
|
||||
|
||||
TDES->TDES_MR = mode;
|
||||
|
||||
|
||||
|
||||
//write keys
|
||||
TDES->TDES_KEY1WR[0] = cryp->key0_buffer[0];
|
||||
TDES->TDES_KEY1WR[1] = cryp->key0_buffer[1];
|
||||
|
||||
if (cryp->key0_size > 8) {
|
||||
TDES->TDES_KEY2WR[0] = cryp->key0_buffer[2];
|
||||
TDES->TDES_KEY2WR[1] = cryp->key0_buffer[3];
|
||||
} else {
|
||||
TDES->TDES_KEY2WR[0] = 0x0;
|
||||
TDES->TDES_KEY2WR[1] = 0x0;
|
||||
}
|
||||
if (cryp->key0_size > 16) {
|
||||
TDES->TDES_KEY3WR[0] = cryp->key0_buffer[4];
|
||||
TDES->TDES_KEY3WR[1] = cryp->key0_buffer[5];
|
||||
} else {
|
||||
TDES->TDES_KEY3WR[0] = 0x0;
|
||||
TDES->TDES_KEY3WR[1] = 0x0;
|
||||
}
|
||||
//initialize vectors registers ( except ECB mode)
|
||||
if (params->mode != TDES_MODE_ECB && vectors != NULL) {
|
||||
TDES->TDES_IVR[0] = vectors[0];
|
||||
TDES->TDES_IVR[1] = vectors[1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (params->algo == TDES_ALGO_XTEA) {
|
||||
TDES->TDES_XTEA_RNDR = TDES_XTEA_RNDR_XTEA_RNDS(32);
|
||||
}
|
||||
|
||||
//enable interrutps
|
||||
TDES->TDES_IER = TDES_IER_DATRDY;
|
||||
|
||||
osalSysLock();
|
||||
|
||||
dmaChannelEnable(cryp->dmarx);
|
||||
dmaChannelEnable(cryp->dmatx);
|
||||
|
||||
osalThreadSuspendS(&cryp->thread);
|
||||
osalSysUnlock();
|
||||
|
||||
osalMutexUnlock(&cryp->mutex);
|
||||
|
||||
return CRY_NOERROR;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_CRY */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
#ifndef CRYPTOLIB_LLD_TDES_H_
|
||||
#define CRYPTOLIB_LLD_TDES_H_
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
TDES_MODE_ECB = 0,
|
||||
TDES_MODE_CBC,
|
||||
TDES_MODE_OFB,
|
||||
TDES_MODE_CFB
|
||||
}tdes_mode_t;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
TDES_CFBS_64 = 0,
|
||||
TDES_CFBS_32,
|
||||
TDES_CFBS_16,
|
||||
TDES_CFBS_8
|
||||
}tdes_cipher_size_t;
|
||||
|
||||
typedef struct {
|
||||
tdes_algo_t algo;
|
||||
tdes_mode_t mode;
|
||||
}tdes_config_t;
|
||||
|
||||
|
||||
extern void sama_tdes_lld_init(CRYDriver *cryp);
|
||||
|
||||
extern cryerror_t sama_tdes_lld_polling(CRYDriver *cryp,
|
||||
tdes_config_t *params,
|
||||
bool encrypt,
|
||||
const uint8_t *data,
|
||||
size_t data_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
extern cryerror_t sama_tdes_lld_dma(CRYDriver *cryp,
|
||||
tdes_config_t *params,
|
||||
bool encrypt,
|
||||
const uint8_t *data,
|
||||
size_t data_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
|
||||
|
||||
#endif /* CRYPTOLIB_LLD_TDES_H_ */
|
|
@ -1,2 +0,0 @@
|
|||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file DMAv1/sama_xdmac.c
|
||||
* @brief Enhanced DMA helper driver code.
|
||||
*
|
||||
* @addtogroup SAMA_DMA
|
||||
* @details DMA sharing helper driver. In the SAMA the DMA channels are a
|
||||
* dedicated resource, this driver allows to allocate and free DMA
|
||||
* channels at runtime.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/* The following macro is only defined if some driver requiring DMA services
|
||||
has been enabled.*/
|
||||
#if defined(SAMA_DMA_REQUIRED) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
sama_dma_channel_t _sama_dma_channel_t[XDMAC_CHANNELS];
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Get content of Global Status register.
|
||||
*
|
||||
* @param[in] xdmacp pointer to DMA controller
|
||||
* @return XDMAC_GS content of Global Status register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define dmaGetGlobal(xdmacp) xdmacp->XDMAC_GS
|
||||
|
||||
/**
|
||||
* @brief Get content of Global Interrupt Status register.
|
||||
*
|
||||
* @param[in] xdmacp pointer to DMA controller
|
||||
* @return XDMAC_GIS content of Global Interrupt Status register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define dmaGetGlobalInt(xdmacp) xdmacp->XDMAC_GIS
|
||||
|
||||
/**
|
||||
* @brief Get content of Channel Interrupt Mask register.
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @return XDMAC_CIMx content of Channel Interrupt Mask register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define dmaGetChannelIntMask(dmachp) \
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CIM
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief XDMAC interrupt handler
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(dmaHandler) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Xdmac *xdmac = XDMAC1;
|
||||
#else
|
||||
Xdmac *xdmac = XDMAC0;
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
uint32_t chan, gis;
|
||||
|
||||
/* Read Global Interrupt Status Register */
|
||||
gis = dmaGetGlobalInt(xdmac);
|
||||
|
||||
for (chan = 0; gis && (chan < XDMAC_CHANNELS); chan++) {
|
||||
sama_dma_channel_t *channel = &_sama_dma_channel_t[chan];
|
||||
|
||||
if (!(gis & (0x1 << chan)))
|
||||
/* There is no pending interrupt for this channel */
|
||||
continue;
|
||||
gis &= ~(0x1 << chan);
|
||||
|
||||
/**
|
||||
* if a channel interrupt is enabled and pending, and a callback exists,
|
||||
* execute it
|
||||
*/
|
||||
uint32_t cis = dmaGetChannelInt(channel) & dmaGetChannelIntMask(channel);
|
||||
if (cis && channel->dma_func)
|
||||
channel->dma_func(channel->dma_param, cis);
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SAMA DMA helper initialization.
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void dmaInit(void) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Xdmac *xdmac = XDMAC1;
|
||||
mtxConfigPeriphSecurity(MATRIX0, ID_XDMAC1, SECURE_PER);
|
||||
#else
|
||||
Xdmac *xdmac = XDMAC0;
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
uint8_t chan;
|
||||
|
||||
for (chan = 0; chan < XDMAC_CHANNELS; chan++) {
|
||||
sama_dma_channel_t *channel = &_sama_dma_channel_t[chan];
|
||||
|
||||
/* Initialization of the specific channel */
|
||||
channel->xdmac = xdmac;
|
||||
channel->chid = chan;
|
||||
channel->state = SAMA_DMA_FREE;
|
||||
channel->dma_func = NULL;
|
||||
|
||||
/* Clear interrupts */
|
||||
dmaGetChannelInt(channel);
|
||||
}
|
||||
|
||||
/* Setting aic source handler */
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
aicSetSourceHandler(ID_XDMAC1, dmaHandler);
|
||||
#else
|
||||
aicSetSourceHandler(ID_XDMAC0, dmaHandler);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the number of transfers to be performed.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
*
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmastp pointer to a sama_dma_channel_t structure
|
||||
* @param[in] size value to be written in the XDMAC_CUBC register
|
||||
*
|
||||
* @special
|
||||
*
|
||||
*/
|
||||
void dmaChannelSetTransactionSize(sama_dma_channel_t *dmachp, size_t n) {
|
||||
|
||||
uint32_t i;
|
||||
uint32_t divisor;
|
||||
/* Single block single microblock */
|
||||
if (n <= XDMAC_MAX_BT_SIZE) {
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CUBC = XDMAC_CUBC_UBLEN(n);
|
||||
}
|
||||
/* Single block multiple microblocks */
|
||||
else {
|
||||
/* If n exceeds XDMAC_MAX_BT_SIZE, split the transfer in microblocks */
|
||||
for (i = 2; i < XDMAC_MAX_BT_SIZE; i++) {
|
||||
divisor = XDMAC_MAX_BT_SIZE / i;
|
||||
if (n % divisor)
|
||||
continue;
|
||||
if ((n / divisor) <= (XDMAC_MAX_BLOCK_LEN + 1)) {
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CUBC = XDMAC_CUBC_UBLEN(i);
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CBC =
|
||||
XDMAC_CBC_BLEN((n / divisor) - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
osalDbgAssert(i != XDMAC_MAX_BT_SIZE, "unsupported DMA transfer size");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a DMA channel.
|
||||
* @details The channel is assigned and, if required, the DMA clock enabled.
|
||||
* The function also enables the IRQ vector associated to the channel
|
||||
* and initializes its priority.
|
||||
* @pre The channel must not be already in use or an error is returned.
|
||||
* @post The channel is allocated and the default ISR handler redirected
|
||||
* to the specified function.
|
||||
* @post The channel ISR vector is enabled and its priority configured.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
*
|
||||
* @param[in] priority IRQ priority mask for the DMA stream
|
||||
* @param[in] func handling function pointer, can be @p NULL
|
||||
* @param[in] param a parameter to be passed to the handling function
|
||||
* @return A pointer to sama_dma_channel_t structure if channel is
|
||||
* assigned or NULL.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
sama_dma_channel_t* dmaChannelAllocate(uint32_t priority,
|
||||
sama_dmaisr_t func,
|
||||
void *param) {
|
||||
|
||||
sama_dma_channel_t *channel = NULL;
|
||||
uint8_t chan;
|
||||
for (chan = 0; chan < XDMAC_CHANNELS; chan++) {
|
||||
channel = &_sama_dma_channel_t[chan];
|
||||
if (channel->state != SAMA_DMA_FREE) {
|
||||
channel = NULL;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (channel != NULL) {
|
||||
/* Marks the channel as allocated.*/
|
||||
channel->state = SAMA_DMA_NOT_FREE;
|
||||
channel->dma_func = func;
|
||||
channel->dma_param = param;
|
||||
|
||||
/* Setting AIC and enabling DMA clocks required by the current channel set.*/
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
aicSetSourcePriority(ID_XDMAC1, priority);
|
||||
aicEnableInt(ID_XDMAC1);
|
||||
pmcEnableXDMAC1();
|
||||
#else
|
||||
aicSetSourcePriority(ID_XDMAC0, priority);
|
||||
aicEnableInt(ID_XDMAC0);
|
||||
pmcEnableXDMAC0();
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/* Enabling channel's interrupt */
|
||||
channel->xdmac->XDMAC_CHID[channel->chid].XDMAC_CIE = XDMAC_CIE_BIE |
|
||||
XDMAC_CIE_WBIE |
|
||||
XDMAC_CIE_RBIE |
|
||||
XDMAC_CIE_ROIE;
|
||||
channel->xdmac->XDMAC_GIE = XDMAC_GIE_IE0 << (channel->chid);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a DMA channel.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post The channel is again available.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void dmaChannelRelease(sama_dma_channel_t *dmachp) {
|
||||
|
||||
osalDbgCheck(dmachp != NULL);
|
||||
/* Check if the channel is free.*/
|
||||
osalDbgAssert(dmachp->state != SAMA_DMA_FREE,
|
||||
"not allocated");
|
||||
|
||||
/* Disables channel */
|
||||
dmaChannelDisable(dmachp);
|
||||
|
||||
/* Disables interrupt */
|
||||
(dmachp)->xdmac->XDMAC_GID = XDMAC_GID_ID0 << ((dmachp)->chid);
|
||||
|
||||
/* Clear dma descriptor */
|
||||
(dmachp)->xdmac->XDMAC_CHID[((dmachp)->chid)].XDMAC_CNDA = 0;
|
||||
(dmachp)->xdmac->XDMAC_CHID[((dmachp)->chid)].XDMAC_CNDC = 0;
|
||||
|
||||
/* Marks the stream as not allocated.*/
|
||||
(dmachp)->state = SAMA_DMA_FREE;
|
||||
}
|
||||
|
||||
#endif /* SAMA_DMA_REQUIRED */
|
||||
|
||||
/** @} */
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file DMAv1/sama_xdmac.h
|
||||
* @brief Enhanced-DMA helper driver header.
|
||||
*
|
||||
* @addtogroup SAMA_XDMAC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_XDMAC_H
|
||||
#define SAMA_XDMAC_H
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief DMA capability.
|
||||
* @details if @p TRUE then the DMA is able of burst transfers, FIFOs,
|
||||
* scatter gather and other advanced features.
|
||||
*/
|
||||
#define SAMA_XDMAC_ADVANCED TRUE
|
||||
|
||||
/**
|
||||
* @brief Number of DMA channels.
|
||||
* @details This is the number of DMA channel for each controller.
|
||||
*/
|
||||
#define XDMAC_CHANNELS (XDMACCHID_NUMBER)
|
||||
|
||||
/**
|
||||
* @brief Max single transfer size.
|
||||
* @details This is the maximum single transfer size supported.
|
||||
*/
|
||||
#define XDMAC_MAX_BT_SIZE 0xFFFFFF
|
||||
|
||||
/**
|
||||
* @brief Max DMA length of the block.
|
||||
* @details This is the maximum length of the block supported.
|
||||
*/
|
||||
#define XDMAC_MAX_BLOCK_LEN 0xFFF
|
||||
|
||||
/**
|
||||
* @brief States of the channel.
|
||||
*/
|
||||
#define SAMA_DMA_FREE 0U
|
||||
#define SAMA_DMA_NOT_FREE 1U
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Descriptor Structure mbr Register.
|
||||
*/
|
||||
#define XDMA_UBC_UBLEN_Pos 0
|
||||
#define XDMA_UBC_UBLEN_Msk (0xffffffu << XDMA_UBC_UBLEN_Pos)
|
||||
#define XDMA_UBC_UBLEN(value) ((XDMA_UBC_UBLEN_Msk \
|
||||
& ((value) << XDMA_UBC_UBLEN_Pos)))
|
||||
#define XDMA_UBC_NDE (0x1u << 24)
|
||||
#define XDMA_UBC_NDE_FETCH_DIS (0x0u << 24)
|
||||
#define XDMA_UBC_NDE_FETCH_EN (0x1u << 24)
|
||||
|
||||
#define XDMA_UBC_NSEN (0x1u << 25)
|
||||
#define XDMA_UBC_NSEN_UNCHANGED (0x0u << 25)
|
||||
#define XDMA_UBC_NSEN_UPDATED (0x1u << 25)
|
||||
|
||||
#define XDMA_UBC_NDEN (0x1u << 26)
|
||||
#define XDMA_UBC_NDEN_UNCHANGED (0x0u << 26)
|
||||
#define XDMA_UBC_NDEN_UPDATED (0x1u << 26)
|
||||
|
||||
#define XDMA_UBC_NVIEW_Pos 27
|
||||
#define XDMA_UBC_NVIEW_Msk (0x3u << XDMA_UBC_NVIEW_Pos)
|
||||
#define XDMA_UBC_NVIEW_NDV0 (0x0u << XDMA_UBC_NVIEW_Pos)
|
||||
#define XDMA_UBC_NVIEW_NDV1 (0x1u << XDMA_UBC_NVIEW_Pos)
|
||||
#define XDMA_UBC_NVIEW_NDV2 (0x2u << XDMA_UBC_NVIEW_Pos)
|
||||
#define XDMA_UBC_NVIEW_NDV3 (0x3u << XDMA_UBC_NVIEW_Pos)
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Linker List Descriptor view0.
|
||||
*/
|
||||
typedef struct {
|
||||
void *mbr_nda; /* Next Descriptor Address */
|
||||
uint32_t mbr_ubc; /* Microblock Control */
|
||||
void *mbr_ta; /* Transfer Address */
|
||||
}lld_view0;
|
||||
|
||||
/**
|
||||
* @brief SAMA5D2 DMA ISR function type.
|
||||
*
|
||||
* @param[in] p parameter for the registered function
|
||||
* @param[in] flags content of the CIS register.
|
||||
*/
|
||||
typedef void (*sama_dmaisr_t)(void *p, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief SAMA5D2 DMA channel descriptor structure.
|
||||
*/
|
||||
typedef struct {
|
||||
Xdmac *xdmac; /**< @brief Associated DMA
|
||||
controller. */
|
||||
uint8_t chid; /**< @brief ID channel */
|
||||
uint8_t state; /**< @brief State channel */
|
||||
sama_dmaisr_t dma_func;
|
||||
void *dma_param;
|
||||
} sama_dma_channel_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Macro Functions
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Gets content of Channel Interrupt Status register.
|
||||
* @note Reading interrupt is equivalent to clearing interrupt.
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @return XDMAC_CISx content of Channel Interrupt Status register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define dmaGetChannelInt(dmachp) \
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CIS
|
||||
|
||||
/**
|
||||
* @brief Returns the number of transfers to be performed.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* @pre The stream must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the stream can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a @p sama_dma_channel_t structure
|
||||
* @return The number of transfers to be performed.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelGetTransactionSize(dmachp) \
|
||||
((size_t)((dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CUBC))
|
||||
|
||||
/**
|
||||
* @brief Associates a source to a DMA channel.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @param[in] addr value to be written in the SA register
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelSetSource(dmachp, addr) { \
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CSA = XDMAC_CSA_SA((uint32_t)addr); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associates a destination to a DMA channel.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @param[in] addr value to be written in the DA register
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelSetDestination(dmachp, addr) { \
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CDA = XDMAC_CDA_DA((uint32_t)addr); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the channel mode settings.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @param[in] mode value to be written in the XDMAC_CC register
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelSetMode(dmachp, mode) { \
|
||||
(dmachp)->xdmac->XDMAC_CHID[(dmachp)->chid].XDMAC_CC = mode; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables DMA channel.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* The hardware disables a channel on transfer completion by clearing
|
||||
* bit XDMAC_GS.STx.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelEnable(dmachp) { \
|
||||
(dmachp)->xdmac->XDMAC_GE = (XDMAC_GE_EN0 << ((dmachp)->chid)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMA channel disable.
|
||||
* @details The function disables the specified channel, waits for the disable
|
||||
* operation to complete and then clears any pending interrupt.
|
||||
* @note This function can be invoked in both ISR or thread context.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define dmaChannelDisable(dmachp) { \
|
||||
(dmachp)->xdmac->XDMAC_GD = XDMAC_GD_DI0 << ((dmachp)->chid); \
|
||||
while ((((dmachp)->xdmac->XDMAC_GS) & (XDMAC_GS_ST0 << (dmachp)->chid)) == 1) { \
|
||||
; \
|
||||
} \
|
||||
dmaGetChannelInt(dmachp); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a memory to memory operation using the specified channel.
|
||||
* @note The default transfer data mode is "byte to byte" but it can be
|
||||
* changed by specifying extra options in the @p mode parameter.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
* @param[in] mode value to be written in the CC register, this value
|
||||
* is implicitly ORed with:
|
||||
* - @p XDMAC_CC_TYPE_MEM_TRAN
|
||||
* - @p XDMAC_CC_SAM_INCREMENTED_AM
|
||||
* - @p XDMAC_CC_DAM_INCREMENTED_AM
|
||||
* - @p XDMAC_CC_SWREQ_SWR_CONNECTED
|
||||
* - @p XDMAC_CC_SIF_AHB_IF0
|
||||
* - @p XDMAC_CC_DIF_AHB_IF0
|
||||
* - @p XDMAC_GE
|
||||
* .
|
||||
* @param[in] src source address
|
||||
* @param[in] dst destination address
|
||||
* @param[in] mode transfer's configuration
|
||||
* @param[in] n number of data units to copy
|
||||
*/
|
||||
#define dmaStartMemCopy(dmachp, mode, src, dst, n) { \
|
||||
dmaChannelSetSource(dmachp, src); \
|
||||
dmaChannelSetDestination(dmachp, dst); \
|
||||
dmaChannelSetTransactionSize(dmachp, n); \
|
||||
dmaChannelSetMode(dmachp, (mode) | \
|
||||
XDMAC_CC_TYPE_MEM_TRAN | XDMAC_CC_SAM_INCREMENTED_AM | \
|
||||
XDMAC_CC_DAM_INCREMENTED_AM | XDMAC_CC_SWREQ_SWR_CONNECTED | \
|
||||
XDMAC_CC_SIF_AHB_IF0 | XDMAC_CC_DIF_AHB_IF0); \
|
||||
dmaChannelEnable(dmachp); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Polled wait for DMA transfer end.
|
||||
* @pre The channel must have been allocated using @p dmaChannelAllocate().
|
||||
* @post After use the channel can be released using @p dmaChannelRelease().
|
||||
*
|
||||
* @param[in] dmachp pointer to a sama_dma_channel_t structure
|
||||
*/
|
||||
#define dmaWaitCompletion(dmachp) { \
|
||||
(dmachp)->xdmac->XDMAC_GID |= XDMAC_GID_ID0 << ((dmachp)->chid); \
|
||||
while ((dmachp)->xdmac->XDMAC_GS & (XDMAC_GS_ST0 << ((dmachp)->chid))) \
|
||||
; \
|
||||
dmaGetChannelInt(dmachp); \
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern sama_dma_channel_t _sama_dma_channel_t[XDMAC_CHANNELS];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void dmaInit(void);
|
||||
void dmaChannelSetTransactionSize(sama_dma_channel_t *dmachp, size_t n);
|
||||
sama_dma_channel_t* dmaChannelAllocate(uint32_t priority,
|
||||
sama_dmaisr_t func,
|
||||
void *param);
|
||||
void dmaChannelRelease(sama_dma_channel_t *dmachp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_DMA_H */
|
||||
|
||||
/** @} */
|
|
@ -1,21 +0,0 @@
|
|||
ifeq ($(USE_HAL_I2C_FALLBACK),yes)
|
||||
# Fallback SW driver.
|
||||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
|
||||
endif
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
|
||||
else
|
||||
# Default HW driver.
|
||||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c
|
||||
endif
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1
|
||||
endif
|
|
@ -1,963 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file I2Cv1/hal_i2c_lld.c
|
||||
* @brief SAMA I2C subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup I2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_I2C || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* SAMA5D2 Clock offset. */
|
||||
#define TWI_CLK_OFFSET 3
|
||||
|
||||
/* Mask for 10-bit address. */
|
||||
#define TWI_ADDR_MASK_10 0x380
|
||||
|
||||
/* Mask for 10-bit address case for DADR field. */
|
||||
#define TWI_ADDR_10_DADR_MASK 0x78
|
||||
#define TWI_ADDR_10_IADR_MASK 0xFF
|
||||
|
||||
/* Mask for internal address check. */
|
||||
#define TWI_INTERNAL_ADDR_MASK 0xFF
|
||||
|
||||
/* Mask for TWI errors interrupt. */
|
||||
#define TWI_ERROR_MASK (TWI_SR_OVRE | TWI_SR_UNRE | \
|
||||
TWI_SR_NACK | TWI_SR_ARBLST | \
|
||||
TWI_SR_TOUT | TWI_SR_PECERR)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
#if !defined ROUND_INT_DIV
|
||||
#define ROUND_INT_DIV(n,d) (((n) + ((d)-1)) / (d))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on TWI registers block.
|
||||
*
|
||||
* @param[in] i2cp pointer to a TWI register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define twiEnableWP(i2cp) { \
|
||||
i2cp->TWI_WPMR = TWI_WPMR_WPKEY_PASSWD | TWI_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on TWI registers block.
|
||||
*
|
||||
* @param[in] i2cp pointer to a TWI register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define twiDisableWP(i2cp) { \
|
||||
i2cp->TWI_WPMR = TWI_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @brief I2C0 driver identifier.*/
|
||||
#if SAMA_I2C_USE_TWIHS0 || defined(__DOXYGEN__)
|
||||
I2CDriver I2CD0;
|
||||
#endif
|
||||
|
||||
/** @brief I2C1 driver identifier.*/
|
||||
#if SAMA_I2C_USE_TWIHS1 || defined(__DOXYGEN__)
|
||||
I2CDriver I2CD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read a byte from TWI_RHR register.
|
||||
*
|
||||
* @param[in] reg pointer to the target register
|
||||
* @param[in] value pointer to the transmit variable
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void i2c_lld_read_byte(volatile const void* reg, uint8_t* value) {
|
||||
*value = *(volatile const uint8_t*)reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a byte to TWI_THR register.
|
||||
*
|
||||
* @param[in] reg pointer to the target register
|
||||
* @param[in] value pointer to the receive variable
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void i2c_lld_write_byte(volatile void* reg, uint8_t value) {
|
||||
*(volatile uint8_t*)reg = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read bytes.
|
||||
* @note Disables WRITE PROTECTION before using
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_read_bytes(I2CDriver *i2cp) {
|
||||
|
||||
if (i2cp->rxbytes == 1) {
|
||||
|
||||
/* Starts and stops the operation for 1 byte read.*/
|
||||
i2cp->i2c->TWI_CR = TWI_CR_START | TWI_CR_STOP;
|
||||
i2cp->i2c->TWI_IER = TWI_IER_TXCOMP;
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0);
|
||||
|
||||
i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, i2cp->rxbuf);
|
||||
}
|
||||
|
||||
if (i2cp->rxbytes == 2) {
|
||||
|
||||
/* Starts the operation.*/
|
||||
i2cp->i2c->TWI_CR = TWI_CR_START;
|
||||
i2cp->i2c->TWI_IER = TWI_IER_TXCOMP;
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0);
|
||||
|
||||
/* Stops the operation and read penultimate byte. */
|
||||
i2cp->i2c->TWI_CR = TWI_CR_STOP;
|
||||
|
||||
i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[0]);
|
||||
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0);
|
||||
|
||||
/* Read last byte. */
|
||||
i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[1]);
|
||||
}
|
||||
|
||||
if (i2cp->rxbytes > 2) {
|
||||
|
||||
/* RX DMA setup.*/
|
||||
dmaChannelSetDestination(i2cp->dmarx, i2cp->rxbuf);
|
||||
dmaChannelSetTransactionSize(i2cp->dmarx, i2cp->rxbytes -2);
|
||||
|
||||
/* Starts the operation.*/
|
||||
i2cp->i2c->TWI_CR = TWI_CR_START;
|
||||
|
||||
/* Start the DMA. */
|
||||
dmaChannelEnable(i2cp->dmarx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write bytes.
|
||||
* @note Disables WRITE PROTECTION before using
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_write_bytes(I2CDriver *i2cp) {
|
||||
|
||||
size_t txsize = i2cp->txbytes;
|
||||
|
||||
if (txsize == 1) {
|
||||
|
||||
i2c_lld_write_byte(&i2cp->i2c->TWI_THR, i2cp->txbuf[0]);
|
||||
|
||||
/* Enable TXCOMP interrupt. */
|
||||
i2cp->i2c->TWI_IER = TWI_IER_TXCOMP;
|
||||
|
||||
i2cp->i2c->TWI_CR = TWI_CR_STOP;
|
||||
|
||||
/* Starts and stops the operation for 1 byte write.*/
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_TXRDY) == 0);
|
||||
}
|
||||
|
||||
if (txsize > 1) {
|
||||
/* RX DMA setup.*/
|
||||
dmaChannelSetSource(i2cp->dmatx, i2cp->txbuf);
|
||||
dmaChannelSetTransactionSize(i2cp->dmatx, (txsize - 1));
|
||||
dmaChannelEnable(i2cp->dmatx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set operation mode of I2C hardware.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_set_opmode(I2CDriver *i2cp) {
|
||||
|
||||
switch (i2cp->config->op_mode) {
|
||||
case OPMODE_I2C:
|
||||
i2cp->i2c->TWI_CR = TWI_CR_SMBDIS;
|
||||
break;
|
||||
case OPMODE_SMBUS:
|
||||
i2cp->i2c->TWI_CR = TWI_CR_SMBEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMA RX end IRQ handler.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_serve_rx_interrupt(I2CDriver *i2cp, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_I2C_DMA_ERROR_HOOK)
|
||||
if ((flags & (XDMAC_CIS_RBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_I2C_DMA_ERROR_HOOK(i2cp);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
/* DMA channel disable. */
|
||||
dmaChannelDisable(i2cp->dmarx);
|
||||
|
||||
/* Cache is enabled */
|
||||
cacheInvalidateRegion(i2cp->rxbuf, i2cp->rxbytes - 1);
|
||||
|
||||
/* Wait for RXRDY flag. */
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0);
|
||||
|
||||
/* Stops the operation and read the last 2 bytes.*/
|
||||
i2cp->i2c->TWI_CR = TWI_CR_STOP;
|
||||
i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[i2cp->rxbytes - 2]);
|
||||
|
||||
/* Wait for the last byte. */
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0);
|
||||
|
||||
/* Enable TXCOMP interrupt. */
|
||||
i2cp->i2c->TWI_IER = TWI_IER_TXCOMP;
|
||||
|
||||
/* Read the last byte. */
|
||||
i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[i2cp->rxbytes - 1]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief DMA TX end IRQ handler.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_serve_tx_interrupt(I2CDriver *i2cp, uint32_t flags) {
|
||||
|
||||
const uint8_t tx_last_byte = i2cp->txbuf[i2cp->txbytes - 1];
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_I2C_DMA_ERROR_HOOK)
|
||||
if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_I2C_DMA_ERROR_HOOK(i2cp);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
dmaChannelDisable(i2cp->dmatx);
|
||||
|
||||
/* Wait for the TX ready flag. */
|
||||
while ((i2cp->i2c->TWI_SR & TWI_SR_TXRDY) == 0);
|
||||
|
||||
/* Stops the operation and transmit the last byte.*/
|
||||
i2cp->i2c->TWI_CR = TWI_CR_STOP;
|
||||
|
||||
i2cp->i2c->TWI_IER = TWI_IER_TXCOMP;
|
||||
|
||||
i2c_lld_write_byte(&i2cp->i2c->TWI_THR, tx_last_byte);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C interrupts handler.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t flags) {
|
||||
|
||||
/* Used only in 1/2 bytes transmissions in order to wake up the thread. */
|
||||
if (flags & TWI_SR_TXCOMP) {
|
||||
_i2c_wakeup_isr(i2cp);
|
||||
}
|
||||
|
||||
i2cp->errors = I2C_NO_ERROR;
|
||||
|
||||
if (flags & TWI_SR_OVRE) /* Overrun error. */
|
||||
i2cp->errors |= I2C_OVERRUN;
|
||||
|
||||
if (flags & TWI_SR_UNRE) /* Underrun error. */
|
||||
i2cp->errors |= I2C_OVERRUN;
|
||||
|
||||
if (flags & TWI_SR_NACK) { /* Acknowledge fail. */
|
||||
i2cp->i2c->TWI_CR = TWI_CR_STOP; /* Setting stop bit. */
|
||||
i2cp->errors |= I2C_ACK_FAILURE;
|
||||
}
|
||||
|
||||
if (flags & TWI_SR_ARBLST) /* Arbitration lost. */
|
||||
i2cp->errors |= I2C_ARBITRATION_LOST;
|
||||
|
||||
if (flags & TWI_SR_TOUT) /* SMBus Timeout. */
|
||||
i2cp->errors |= I2C_TIMEOUT;
|
||||
|
||||
if (flags & TWI_SR_PECERR) /* PEC error. */
|
||||
i2cp->errors |= I2C_PEC_ERROR;
|
||||
|
||||
/* If some error has been identified then sends wakes the waiting thread.*/
|
||||
if (i2cp->errors != I2C_NO_ERROR)
|
||||
_i2c_wakeup_error_isr(i2cp);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS0 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief TWIHS0 interrupt handler.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TWIHS0_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr = I2CD0.i2c->TWI_SR;
|
||||
|
||||
I2CD0.i2c->TWI_IDR = TWI_IDR_TXCOMP;
|
||||
|
||||
i2c_lld_serve_interrupt(&I2CD0, sr);
|
||||
aicAckInt();
|
||||
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* SAMA_I2C_USE_TWIHS0 */
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS1 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief TWIHS1 interrupt handler.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TWIHS1_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr = I2CD1.i2c->TWI_SR;
|
||||
|
||||
I2CD1.i2c->TWI_IDR = TWI_IDR_TXCOMP;
|
||||
|
||||
i2c_lld_serve_interrupt(&I2CD1, sr);
|
||||
aicAckInt();
|
||||
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
#endif /* SAMA_I2C_USE_TWIHS1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level I2C driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_init(void) {
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS0
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TWIHS0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
i2cObjectInit(&I2CD0);
|
||||
I2CD0.thread = NULL;
|
||||
I2CD0.i2c = TWIHS0;
|
||||
I2CD0.dmarx = NULL;
|
||||
I2CD0.dmatx = NULL;
|
||||
I2CD0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_TWIHS0_RX);
|
||||
I2CD0.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_TWIHS0_TX);
|
||||
#endif /* SAMA_I2C_USE_TWIHS0 */
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS1
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TWIHS1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
i2cObjectInit(&I2CD1);
|
||||
I2CD1.thread = NULL;
|
||||
I2CD1.i2c = TWIHS1;
|
||||
I2CD1.dmarx = NULL;
|
||||
I2CD1.dmatx = NULL;
|
||||
I2CD1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_TWIHS1_RX);
|
||||
I2CD1.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_TWIHS1_TX);
|
||||
#endif /* SAMA_I2C_USE_TWIHS1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the I2C peripheral.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_start(I2CDriver *i2cp) {
|
||||
|
||||
uint32_t ck_div, clh_div, hold;
|
||||
|
||||
/* If in stopped state then enables the I2C and DMA clocks.*/
|
||||
if (i2cp->state == I2C_STOP) {
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS0
|
||||
if (&I2CD0 == i2cp) {
|
||||
|
||||
i2cp->dmarx = dmaChannelAllocate(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)i2c_lld_serve_rx_interrupt,
|
||||
(void *)i2cp);
|
||||
osalDbgAssert(i2cp->dmarx != NULL, "no channel allocated");
|
||||
|
||||
i2cp->dmatx = dmaChannelAllocate(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)i2c_lld_serve_tx_interrupt,
|
||||
(void *)i2cp);
|
||||
osalDbgAssert(i2cp->dmatx != NULL, "no channel allocated");
|
||||
|
||||
pmcEnableTWIHS0();
|
||||
/* To prevent spurious interrupt */
|
||||
aicSetIntSourceType(ID_TWIHS0, EXT_NEGATIVE_EDGE);
|
||||
aicSetSourcePriority(ID_TWIHS0, SAMA_I2C_TWIHS0_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TWIHS0, SAMA_TWIHS0_HANDLER);
|
||||
aicEnableInt(ID_TWIHS0);
|
||||
}
|
||||
#endif /* SAMA_I2C_USE_TWIHS0 */
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS1
|
||||
if (&I2CD1 == i2cp) {
|
||||
|
||||
i2cp->dmarx = dmaChannelAllocate(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)i2c_lld_serve_rx_interrupt,
|
||||
(void *)i2cp);
|
||||
osalDbgAssert(i2cp->dmarx != NULL, "no channel allocated");
|
||||
|
||||
i2cp->dmatx = dmaChannelAllocate(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)i2c_lld_serve_tx_interrupt,
|
||||
(void *)i2cp);
|
||||
osalDbgAssert(i2cp->dmatx != NULL, "no channel allocated");
|
||||
|
||||
pmcEnableTWIHS1();
|
||||
/* To prevent spurious interrupt */
|
||||
aicSetIntSourceType(ID_TWIHS1, EXT_NEGATIVE_EDGE);
|
||||
aicSetSourcePriority(ID_TWIHS1, SAMA_I2C_TWIHS1_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TWIHS1, SAMA_TWIHS1_HANDLER);
|
||||
aicEnableInt(ID_TWIHS1);
|
||||
}
|
||||
#endif /* SAMA_I2C_USE_TWIHS1 */
|
||||
}
|
||||
|
||||
/* Set mode */
|
||||
dmaChannelSetMode(i2cp->dmarx, i2cp->rxdmamode);
|
||||
dmaChannelSetSource(i2cp->dmarx, &i2cp->i2c->TWI_RHR);
|
||||
|
||||
dmaChannelSetMode(i2cp->dmatx, i2cp->txdmamode);
|
||||
dmaChannelSetDestination(i2cp->dmatx, &i2cp->i2c->TWI_THR);
|
||||
|
||||
/* Disable write protection. */
|
||||
twiDisableWP(i2cp->i2c);
|
||||
|
||||
/* TWI software reset */
|
||||
i2cp->i2c->TWI_CR = TWI_CR_SWRST;
|
||||
|
||||
/* TWI set operation mode. */
|
||||
i2c_lld_set_opmode(i2cp);
|
||||
|
||||
/* Configure dummy slave address */
|
||||
i2cp->i2c->TWI_MMR = 0;
|
||||
|
||||
/* Compute clock */
|
||||
for (ck_div = 0; ck_div < 7; ck_div++) {
|
||||
clh_div = ((SAMA_TWIHSxCLK / i2cp->config->clock_speed) - 2 * (TWI_CLK_OFFSET)) >> ck_div;
|
||||
if (clh_div <= 511) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute holding time (I2C spec requires 300ns) */
|
||||
hold = TWI_CWGR_HOLD(ROUND_INT_DIV((uint32_t)(0.3 * SAMA_TWIHSxCLK), 1000000) - 3);
|
||||
|
||||
/* Configure clock */
|
||||
i2cp->i2c->TWI_CWGR = TWI_CWGR_CKDIV(ck_div) |
|
||||
TWI_CWGR_CHDIV(clh_div >> 1) |
|
||||
TWI_CWGR_CLDIV(clh_div >> 1) |
|
||||
hold;
|
||||
|
||||
/* Clear status flag */
|
||||
i2cp->i2c->TWI_SR;
|
||||
|
||||
/* Enable Interrupt. */
|
||||
i2cp->i2c->TWI_IER = TWI_ERROR_MASK;
|
||||
|
||||
/* Set master mode */
|
||||
i2cp->i2c->TWI_CR = TWI_CR_SVDIS;
|
||||
i2cp->i2c->TWI_CR = TWI_CR_MSEN;
|
||||
|
||||
/* Enable write protection. */
|
||||
twiEnableWP(i2cp->i2c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the I2C peripheral.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void i2c_lld_stop(I2CDriver *i2cp) {
|
||||
|
||||
/* If not in stopped state then disables the I2C clock.*/
|
||||
if (i2cp->state != I2C_STOP) {
|
||||
|
||||
/* Disable write protection. */
|
||||
twiDisableWP(i2cp->i2c);
|
||||
|
||||
/* I2C disable.*/
|
||||
|
||||
/* Disable interrupts. */
|
||||
i2cp->i2c->TWI_IDR = TWI_ERROR_MASK;
|
||||
|
||||
/* TWI software reset. */
|
||||
i2cp->i2c->TWI_CR = TWI_CR_SWRST;
|
||||
i2cp->i2c->TWI_MMR = 0;
|
||||
|
||||
/* DMA channel release. */
|
||||
dmaChannelRelease(i2cp->dmatx);
|
||||
dmaChannelRelease(i2cp->dmarx);
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS0
|
||||
if (&I2CD0 == i2cp) {
|
||||
pmcDisableTWIHS0();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS1
|
||||
if (&I2CD1 == i2cp) {
|
||||
pmcDisableTWIHS1();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable write protection. */
|
||||
twiEnableWP(i2cp->i2c);
|
||||
}
|
||||
|
||||
i2cp->txbuf = NULL;
|
||||
i2cp->rxbuf = NULL;
|
||||
i2cp->txbytes = 0;
|
||||
i2cp->rxbytes = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receives data via the I2C bus as master.
|
||||
* @details
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] addr slave device address
|
||||
* @param[out] rxbuf pointer to the receive buffer
|
||||
* @param[in] rxbytes number of bytes to be received
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if the function succeeded.
|
||||
* @retval MSG_RESET if one or more I2C errors occurred, the errors can
|
||||
* be retrieved using @p i2cGetErrors().
|
||||
* @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
|
||||
* timeout the driver must be stopped and restarted
|
||||
* because the bus is in an uncertain state</b>.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
sysinterval_t timeout) {
|
||||
|
||||
osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
i2cp->txbuf = NULL;
|
||||
i2cp->rxbuf = rxbuf;
|
||||
i2cp->txbytes = 0;
|
||||
i2cp->rxbytes = rxbytes;
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
* TODO: remove when size assert works
|
||||
*/
|
||||
if (rxbytes & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) rxbuf, rxbytes);
|
||||
}
|
||||
|
||||
systime_t start, end;
|
||||
|
||||
/* Resetting error flags for this transfer.*/
|
||||
i2cp->errors = I2C_NO_ERROR;
|
||||
|
||||
/* Disable write protection. */
|
||||
twiDisableWP(i2cp->i2c);
|
||||
|
||||
/* Compute device address and/or internal address. */
|
||||
i2cp->i2c->TWI_MMR = 0;
|
||||
|
||||
if ((addr & TWI_ADDR_MASK_10) != 0) {
|
||||
/* 10-bit address. */
|
||||
if (i2cp->config->op_mode == OPMODE_I2C) {
|
||||
|
||||
/* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in MMR_IADRSZ as 1. */
|
||||
i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) |
|
||||
TWI_MMR_IADRSZ_1_BYTE | TWI_MMR_MREAD;
|
||||
i2cp->i2c->TWI_IADR = TWI_ADDR_10_IADR_MASK & addr;
|
||||
|
||||
} else if (i2cp->config->op_mode == OPMODE_SMBUS)
|
||||
osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode");
|
||||
|
||||
} else {
|
||||
/* 7-bit address. */
|
||||
/* Store slave device address in MMR_DADR. */
|
||||
i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr);
|
||||
|
||||
/* Configure read direction. */
|
||||
i2cp->i2c->TWI_MMR |= TWI_MMR_MREAD;
|
||||
}
|
||||
/* Releases the lock from high level driver.*/
|
||||
osalSysUnlock();
|
||||
|
||||
/* Calculating the time window for the timeout on the busy bus condition.*/
|
||||
start = osalOsGetSystemTimeX();
|
||||
end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT));
|
||||
|
||||
/* Waits until BUSY flag is reset or, alternatively, for a timeout
|
||||
condition.*/
|
||||
while (true) {
|
||||
osalSysLock();
|
||||
|
||||
/* If the bus is not busy then the operation can continue, note, the
|
||||
loop is exited in the locked state.*/
|
||||
if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY))
|
||||
break;
|
||||
|
||||
/* If the system time went outside the allowed window then a timeout
|
||||
condition is returned.*/
|
||||
if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end))
|
||||
return MSG_TIMEOUT;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
i2c_lld_read_bytes(i2cp);
|
||||
|
||||
/* Enable write protection. */
|
||||
twiEnableWP(i2cp->i2c);
|
||||
|
||||
/* Waits for the operation completion or a timeout.*/
|
||||
return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmits data via the I2C bus as master.
|
||||
* @details When performing reading through write you can not write more than
|
||||
* 3 bytes of data to I2C slave. This is SAMA platform limitation.
|
||||
* Internal address bytes must be set in txbuf from LSB (position 0 of the buffer) to MSB
|
||||
* (position 1 or 2 of the buffer depending from the number of internal address bytes.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
* @param[in] addr slave device address
|
||||
* @param[in] txbuf pointer to the transmit buffer
|
||||
* @param[in] txbytes number of bytes to be transmitted
|
||||
* @param[out] rxbuf pointer to the receive buffer
|
||||
* @param[in] rxbytes number of bytes to be received
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if the function succeeded.
|
||||
* @retval MSG_RESET if one or more I2C errors occurred, the errors can
|
||||
* be retrieved using @p i2cGetErrors().
|
||||
* @retval MSG_TIMEOUT if a timeout occurred before operation end. <b>After a
|
||||
* timeout the driver must be stopped and restarted
|
||||
* because the bus is in an uncertain state</b>.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
sysinterval_t timeout) {
|
||||
|
||||
osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned");
|
||||
osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
i2cp->txbuf = txbuf;
|
||||
i2cp->rxbuf = rxbuf;
|
||||
i2cp->txbytes = txbytes;
|
||||
i2cp->rxbytes = rxbytes;
|
||||
|
||||
/* Cache is enabled */
|
||||
cacheCleanRegion((uint8_t *)i2cp->txbuf, txbytes);
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
* TODO: remove when size assert works
|
||||
*/
|
||||
if (rxbytes & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) rxbuf, rxbytes);
|
||||
}
|
||||
|
||||
systime_t start, end;
|
||||
|
||||
/* Resetting error flags for this transfer.*/
|
||||
i2cp->errors = I2C_NO_ERROR;
|
||||
|
||||
/* Disable write protection. */
|
||||
twiDisableWP(i2cp->i2c);
|
||||
|
||||
/* prepare to read through write operation */
|
||||
if (rxbytes > 0){
|
||||
|
||||
osalDbgAssert(txbytes <= 3, "Number of internal address bytes not supported. Max number of internal address bytes is 3.");
|
||||
|
||||
i2cp->i2c->TWI_MMR = 0;
|
||||
|
||||
/* Compute slave address and internal addresses. */
|
||||
|
||||
/* Internal address of I2C slave was set in special Atmel registers.
|
||||
* Now we must call read function. The I2C cell automatically sends
|
||||
* bytes from IADR register to bus and issues repeated start. */
|
||||
|
||||
if ((addr & TWI_ADDR_MASK_10) != 0) {
|
||||
/* 10-bit address. */
|
||||
if (i2cp->config->op_mode == OPMODE_I2C) {
|
||||
|
||||
uint16_t mem_addr = 0;
|
||||
|
||||
osalDbgAssert(txbytes <= 2, "Number of internal address bytes not supported");
|
||||
|
||||
/* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in
|
||||
* MMR_IADRSZ as 1 + slave internal addresses. */
|
||||
i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) |
|
||||
TWI_MMR_IADRSZ(txbytes + 1);
|
||||
|
||||
if(txbytes == 1)
|
||||
mem_addr = i2cp->txbuf[0];
|
||||
|
||||
else if(txbytes == 2)
|
||||
mem_addr = i2cp->txbuf[0] | (i2cp->txbuf[1] << 8);
|
||||
|
||||
/* Store the rest of the 10-bit address in IADR register. Also store the internal slave address bytes. */
|
||||
i2cp->i2c->TWI_IADR = (TWI_ADDR_10_IADR_MASK & addr) | (mem_addr << 8);
|
||||
|
||||
} else if (i2cp->config->op_mode == OPMODE_SMBUS)
|
||||
osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode");
|
||||
|
||||
} else {
|
||||
/* 7-bit address. */
|
||||
i2cp->i2c->TWI_MMR |= txbytes << 8;
|
||||
|
||||
/* Store internal slave address in TWI_IADR registers */
|
||||
i2cp->i2c->TWI_IADR = 0;
|
||||
while (txbytes > 0){
|
||||
i2cp->i2c->TWI_IADR = (i2cp->i2c->TWI_IADR << 8);
|
||||
i2cp->i2c->TWI_IADR |= *(txbuf++);
|
||||
txbytes--;
|
||||
}
|
||||
/* Store slave device address in MMR_DADR. */
|
||||
i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
/* Configure read direction. */
|
||||
i2cp->i2c->TWI_MMR |= TWI_MMR_MREAD;
|
||||
|
||||
/* Releases the lock from high level driver.*/
|
||||
osalSysUnlock();
|
||||
|
||||
/* Calculating the time window for the timeout on the busy bus condition.*/
|
||||
start = osalOsGetSystemTimeX();
|
||||
end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT));
|
||||
|
||||
/* Waits until BUSY flag is reset or, alternatively, for a timeout
|
||||
condition.*/
|
||||
while (true) {
|
||||
osalSysLock();
|
||||
|
||||
/* If the bus is not busy then the operation can continue, note, the
|
||||
loop is exited in the locked state.*/
|
||||
if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY))
|
||||
break;
|
||||
|
||||
/* If the system time went outside the allowed window then a timeout
|
||||
condition is returned.*/
|
||||
if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end))
|
||||
return MSG_TIMEOUT;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
i2c_lld_read_bytes(i2cp);
|
||||
|
||||
/* Enable write protection. */
|
||||
twiEnableWP(i2cp->i2c);
|
||||
|
||||
/* Waits for the operation completion or a timeout.*/
|
||||
return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
|
||||
|
||||
} else {
|
||||
/* Compute device slave address. Internal slave address are sent as data. */
|
||||
|
||||
i2cp->i2c->TWI_MMR = 0;
|
||||
|
||||
if ((addr & TWI_ADDR_MASK_10) != 0) {
|
||||
/* 10-bit address. */
|
||||
if (i2cp->config->op_mode == OPMODE_I2C) {
|
||||
|
||||
/* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in MMR_IADRSZ as 1. */
|
||||
i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) |
|
||||
TWI_MMR_IADRSZ_1_BYTE;
|
||||
i2cp->i2c->TWI_IADR = TWI_ADDR_10_IADR_MASK & addr;
|
||||
|
||||
} else if (i2cp->config->op_mode == OPMODE_SMBUS)
|
||||
osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode");
|
||||
|
||||
} else {
|
||||
/* 7-bit address. */
|
||||
/* Store slave device address in MMR_DADR. */
|
||||
i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr);
|
||||
}
|
||||
|
||||
/* Releases the lock from high level driver.*/
|
||||
osalSysUnlock();
|
||||
|
||||
/* Calculating the time window for the timeout on the busy bus condition.*/
|
||||
start = osalOsGetSystemTimeX();
|
||||
end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT));
|
||||
|
||||
/* Waits until BUSY flag is reset or, alternatively, for a timeout
|
||||
condition.*/
|
||||
while (true) {
|
||||
osalSysLock();
|
||||
|
||||
/* If the bus is not busy then the operation can continue, note, the
|
||||
loop is exited in the locked state.*/
|
||||
if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY))
|
||||
break;
|
||||
|
||||
/* If the system time went outside the allowed window then a timeout
|
||||
condition is returned.*/
|
||||
if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end))
|
||||
return MSG_TIMEOUT;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
i2c_lld_write_bytes(i2cp);
|
||||
|
||||
/* Enable write protection. */
|
||||
twiEnableWP(i2cp->i2c);
|
||||
|
||||
/* Waits for the operation completion or a timeout.*/
|
||||
return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_I2C */
|
||||
|
||||
/** @} */
|
|
@ -1,277 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file I2Cv1/hal_i2c_lld.h
|
||||
* @brief SAMA I2C subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup I2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_I2C_LLD_H
|
||||
#define HAL_I2C_LLD_H
|
||||
|
||||
#if HAL_USE_I2C || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief I2C0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TWIHS0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_USE_TWIHS0) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_USE_TWIHS0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TWIHS1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_USE_TWIHS1) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_USE_TWIHS1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C timeout on busy condition in milliseconds.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_BUSY_TIMEOUT 50
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_TWIHS0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_TWIHS0_IRQ_PRIORITY 6
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_TWIHS1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_TWIHS1_IRQ_PRIORITY 6
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C0 DMA IRQ priority (0..7|lowest..highest).
|
||||
* @note The priority level is used for both the TX and RX DMA channels.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY 6
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C1 DMA IRQ priority (0..7|lowest..highest).
|
||||
* @note The priority level is used for both the TX and RX DMA streams.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY 6
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C DMA error hook.
|
||||
* @note The default action for DMA errors is a system halt because DMA
|
||||
* error can only happen because programming errors.
|
||||
*/
|
||||
#if !defined(SAMA_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||
#define SAMA_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @brief error checks */
|
||||
|
||||
#if !SAMA_I2C_USE_TWIHS0 && !SAMA_I2C_USE_TWIHS1
|
||||
#error "I2C driver activated but no TWIHS peripheral assigned"
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA_DMA_REQUIRED)
|
||||
#define SAMA_DMA_REQUIRED
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type representing an I2C address.
|
||||
*/
|
||||
typedef uint32_t i2caddr_t;
|
||||
|
||||
/**
|
||||
* @brief Type of I2C driver condition flags.
|
||||
*/
|
||||
typedef uint32_t i2cflags_t;
|
||||
|
||||
/**
|
||||
* @brief Supported modes for the I2C bus.
|
||||
*/
|
||||
typedef enum {
|
||||
OPMODE_I2C = 1,
|
||||
OPMODE_SMBUS = 2,
|
||||
} i2copmode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of I2C driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/* End of the mandatory fields.*/
|
||||
i2copmode_t op_mode; /**< @brief Specifies the I2C mode. */
|
||||
uint32_t clock_speed; /**< @brief Specifies the clock frequency.
|
||||
@note Must be set to a value lower
|
||||
than 400kHz. */
|
||||
} I2CConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an I2C driver.
|
||||
*/
|
||||
typedef struct I2CDriver I2CDriver;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an I2C driver.
|
||||
*/
|
||||
struct I2CDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
i2cstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const I2CConfig *config;
|
||||
/**
|
||||
* @brief Error flags.
|
||||
*/
|
||||
i2cflags_t errors;
|
||||
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the bus.
|
||||
*/
|
||||
mutex_t mutex;
|
||||
#endif /* I2C_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(I2C_DRIVER_EXT_FIELDS)
|
||||
I2C_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Thread waiting for I/O completion.
|
||||
*/
|
||||
thread_reference_t thread;
|
||||
/**
|
||||
* @brief Number of bytes in TX phase.
|
||||
*/
|
||||
size_t txbytes;
|
||||
/**
|
||||
* @brief Number of bytes in RX phase.
|
||||
*/
|
||||
size_t rxbytes;
|
||||
/**
|
||||
* @brief Pointer to the TX buffer location.
|
||||
*/
|
||||
const uint8_t *txbuf;
|
||||
/**
|
||||
* @brief Pointer to the RX buffer location.
|
||||
*/
|
||||
uint8_t *rxbuf;
|
||||
/**
|
||||
* @brief Receive DMA stream.
|
||||
*/
|
||||
sama_dma_channel_t *dmarx;
|
||||
/**
|
||||
* @brief Transmit DMA stream.
|
||||
*/
|
||||
sama_dma_channel_t *dmatx;
|
||||
/**
|
||||
* @brief RX DMA mode bit mask.
|
||||
*/
|
||||
uint32_t rxdmamode;
|
||||
/**
|
||||
* @brief TX DMA mode bit mask.
|
||||
*/
|
||||
uint32_t txdmamode;
|
||||
/**
|
||||
* @brief Pointer to the TWIHSx registers block.
|
||||
*/
|
||||
Twi *i2c;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Get errors from I2C driver.
|
||||
*
|
||||
* @param[in] i2cp pointer to the @p I2CDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
#if SAMA_I2C_USE_TWIHS0
|
||||
extern I2CDriver I2CD0;
|
||||
#endif
|
||||
|
||||
#if SAMA_I2C_USE_TWIHS1
|
||||
extern I2CDriver I2CD1;
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void i2c_lld_init(void);
|
||||
void i2c_lld_start(I2CDriver *i2cp);
|
||||
void i2c_lld_stop(I2CDriver *i2cp);
|
||||
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
const uint8_t *txbuf, size_t txbytes,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
sysinterval_t timeout);
|
||||
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
|
||||
uint8_t *rxbuf, size_t rxbytes,
|
||||
sysinterval_t timeout);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_I2C */
|
||||
|
||||
#endif /* HAL_I2C_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1
|
|
@ -1,852 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MACv1/hal_mac_lld.c
|
||||
* @brief SAMA low level MAC driver code.
|
||||
*
|
||||
* @addtogroup MAC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
#include "hal_mii.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* @brief Buffer size.
|
||||
*/
|
||||
#define BUFFER_SIZE ((((SAMA_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
|
||||
|
||||
/*
|
||||
* @brief NO CACHE attribute
|
||||
*/
|
||||
#if !defined(NO_CACHE)
|
||||
#define NO_CACHE __attribute__((section (".nocache")))
|
||||
#endif
|
||||
|
||||
/* MII divider optimal value.*/
|
||||
#if (SAMA_GMAC0CLK <= 20000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_8
|
||||
#elif (SAMA_GMAC0CLK <= 40000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_16
|
||||
#elif (SAMA_GMAC0CLK <= 80000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_32
|
||||
#elif (SAMA_GMAC0CLK <= 120000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_48
|
||||
#elif (SAMA_GMAC0CLK <= 160000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_64
|
||||
#elif (SAMA_GMAC0CLK <= 240000000)
|
||||
#define GMAC_CLK GMAC_NCFGR_CLK_MCK_96
|
||||
#else
|
||||
#error "MCK too high, cannot configure MDC clock"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BV1000GT boards use phy address 0
|
||||
*/
|
||||
#if defined(BOARD_ATSAM5D28_XULT)
|
||||
#define BOARD_PHY_ADDRESS 0
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Ethernet driver 0.
|
||||
*/
|
||||
MACDriver ETHD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static const uint8_t default_mac_address[] = {0x54, 0x54, 0x08, 0x34, 0x1f, 0x3a};
|
||||
|
||||
/*
|
||||
* In terms of AMBA AHB operation, the descriptors are read from memory using
|
||||
* a single 32-bit AHB access. The descriptors should be aligned at 32-bit
|
||||
* boundaries and the descriptors are written to using two individual non
|
||||
* sequential accesses.
|
||||
*/
|
||||
|
||||
/* Rx descriptor list */
|
||||
NO_CACHE ALIGNED_VAR(4)
|
||||
static sama_eth_rx_descriptor_t __eth_rd[SAMA_MAC_RECEIVE_BUFFERS];
|
||||
|
||||
/* Tx descriptor list */
|
||||
NO_CACHE ALIGNED_VAR(4)
|
||||
static sama_eth_tx_descriptor_t __eth_td[SAMA_MAC_TRANSMIT_BUFFERS];
|
||||
NO_CACHE ALIGNED_VAR(4)
|
||||
static sama_eth_tx_descriptor_t __eth_td1[1];
|
||||
NO_CACHE ALIGNED_VAR(4)
|
||||
static sama_eth_tx_descriptor_t __eth_td2[1];
|
||||
|
||||
NO_CACHE
|
||||
static uint32_t __eth_rb[SAMA_MAC_RECEIVE_BUFFERS][BUFFER_SIZE];
|
||||
NO_CACHE
|
||||
static uint32_t __eth_tb[SAMA_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE];
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Waits for phy management logic idle.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define phyWaitIdle() { \
|
||||
while ((GMAC0->GMAC_NSR & GMAC_NSR_IDLE) == 0) { \
|
||||
; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Writes a PHY register.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[in] reg_addr register address
|
||||
* @param[in] value new register value
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mii_write(MACDriver *macp, uint32_t reg_addr, uint32_t value) {
|
||||
|
||||
phyWaitIdle();
|
||||
|
||||
/* Write maintenance register (Clause 22) */
|
||||
GMAC0->GMAC_MAN = GMAC_MAN_CLTTO | GMAC_MAN_OP(1) | GMAC_MAN_WTN(2) |
|
||||
GMAC_MAN_PHYA(macp->phyaddr) | GMAC_MAN_REGA(reg_addr) |
|
||||
GMAC_MAN_DATA(value);
|
||||
phyWaitIdle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a PHY register.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[in] reg_addr register address
|
||||
*
|
||||
* @return The PHY register content.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint32_t mii_read(MACDriver *macp, uint32_t reg_addr) {
|
||||
|
||||
phyWaitIdle();
|
||||
|
||||
/* Read maintenance register */
|
||||
GMAC0->GMAC_MAN = GMAC_MAN_CLTTO | GMAC_MAN_OP(2) | GMAC_MAN_WTN(2) |
|
||||
GMAC_MAN_PHYA(macp->phyaddr) | GMAC_MAN_REGA(reg_addr);
|
||||
phyWaitIdle();
|
||||
|
||||
return (uint32_t) ((GMAC0->GMAC_MAN) & GMAC_MAN_DATA_Msk >> GMAC_MAN_DATA_Pos);
|
||||
}
|
||||
|
||||
#if !defined(BOARD_PHY_ADDRESS)
|
||||
/**
|
||||
* @brief PHY address detection.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*/
|
||||
static void mii_find_phy(MACDriver *macp) {
|
||||
uint32_t i;
|
||||
|
||||
#if SAMA_MAC_PHY_TIMEOUT > 0
|
||||
unsigned n = SAMA_MAC_PHY_TIMEOUT;
|
||||
do {
|
||||
#endif
|
||||
for (i = 1U; i < 31U; i++) {
|
||||
macp->phyaddr = i;
|
||||
if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) &&
|
||||
((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if SAMA_MAC_PHY_TIMEOUT > 0
|
||||
n--;
|
||||
} while (n > 0U);
|
||||
#endif
|
||||
macp->phyaddr = 0;
|
||||
return;
|
||||
/* Wrong or defective board.*/
|
||||
osalSysHalt("MAC failure");
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MAC address setup.
|
||||
*
|
||||
* @param[in] p pointer to a six bytes buffer containing the MAC
|
||||
* address
|
||||
*/
|
||||
static void mac_lld_set_address(const uint8_t *p) {
|
||||
|
||||
/* MAC address configuration, only a single address comparator is used,
|
||||
hash table not used.*/
|
||||
GMAC0->GMAC_SA[0].GMAC_SAB = (p[3] << 24) | (p[2] << 16) |
|
||||
(p[1] << 8) | p[0];
|
||||
GMAC0->GMAC_SA[0].GMAC_SAT = (p[5] << 8) | p[4];
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
OSAL_IRQ_HANDLER(SAMA_ETH_HANDLER) {
|
||||
uint32_t isr;
|
||||
uint32_t rsr;
|
||||
uint32_t tsr;
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
isr = GMAC0->GMAC_ISR;
|
||||
rsr = GMAC0->GMAC_RSR;
|
||||
tsr = GMAC0->GMAC_TSR;
|
||||
|
||||
if (isr & GMAC_ISR_RCOMP) {
|
||||
/* Data Received.*/
|
||||
osalSysLockFromISR();
|
||||
/* Clear Status Register */
|
||||
GMAC0->GMAC_RSR = rsr;
|
||||
osalThreadDequeueAllI(ÐD0.rdqueue, MSG_RESET);
|
||||
#if MAC_USE_EVENTS
|
||||
osalEventBroadcastFlagsI(ÐD0.rdevent, 0);
|
||||
#endif
|
||||
osalSysUnlockFromISR();
|
||||
}
|
||||
|
||||
if (isr & GMAC_ISR_TCOMP) {
|
||||
/* Data Transmitted.*/
|
||||
osalSysLockFromISR();
|
||||
/* Clear Status Register */
|
||||
GMAC0->GMAC_TSR = tsr;
|
||||
osalThreadDequeueAllI(ÐD0.tdqueue, MSG_RESET);
|
||||
osalSysUnlockFromISR();
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level MAC initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_init(void) {
|
||||
|
||||
unsigned i;
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_GMAC0, SECURE_PER);
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_GMAC0_Q1, SECURE_PER);
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_GMAC0_Q2, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
macObjectInit(ÐD0);
|
||||
ETHD0.link_up = false;
|
||||
|
||||
/* Descriptor tables are initialized in chained mode, note that the status
|
||||
word is not initialized here but in mac_lld_start().*/
|
||||
for (i = 0; i < SAMA_MAC_RECEIVE_BUFFERS; i++) {
|
||||
__eth_rd[i].rdes0 = ((uint32_t)__eth_rb[i]) & (SAMA_RDES0_RBAP_MASK);
|
||||
/* Status reset */
|
||||
__eth_rd[i].rdes1 = 0;
|
||||
/* For last buffer wrap is set */
|
||||
if (i == (SAMA_MAC_RECEIVE_BUFFERS - 1)){
|
||||
__eth_rd[i].rdes0 |= SAMA_RDES0_WRAP;
|
||||
}
|
||||
}
|
||||
|
||||
__eth_td1[0].tdes1 = 0;
|
||||
__eth_td2[0].tdes1 = 0;
|
||||
|
||||
for (i = 0; i < SAMA_MAC_TRANSMIT_BUFFERS; i++) {
|
||||
__eth_td[i].tdes0 = (uint32_t)__eth_tb[i];
|
||||
/* Status reset */
|
||||
__eth_td[i].tdes1 = 0;
|
||||
/* For last buffer wrap is set */
|
||||
if (i == (SAMA_MAC_TRANSMIT_BUFFERS - 1)){
|
||||
__eth_td[i].tdes1 |= SAMA_TDES1_WRAP;
|
||||
__eth_td1[0].tdes1 |= SAMA_TDES1_WRAP;
|
||||
__eth_td2[0].tdes1 |= SAMA_TDES1_WRAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* MAC clocks temporary activation.*/
|
||||
pmcEnableETH0();
|
||||
|
||||
/* Configures MDIO clock */
|
||||
GMAC0->GMAC_NCFGR = (GMAC0->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | GMAC_CLK;
|
||||
|
||||
/* Enables management port */
|
||||
GMAC0->GMAC_NCR |= GMAC_NCR_MPE;
|
||||
|
||||
/* Selection of the RMII or MII mode based on info exported by board.h.*/
|
||||
#if defined(BOARD_PHY_RMII)
|
||||
GMAC0->GMAC_UR = GMAC_UR_RMII;
|
||||
#else
|
||||
GMAC0->GMAC_UR &= ~GMAC_UR_RMII;
|
||||
#endif
|
||||
|
||||
/* PHY address setup.*/
|
||||
#if defined(BOARD_PHY_ADDRESS)
|
||||
ETHD0.phyaddr = BOARD_PHY_ADDRESS;
|
||||
#else
|
||||
mii_find_phy(ÐD0);
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_PHY_RESET)
|
||||
/* PHY board-specific reset procedure.*/
|
||||
BOARD_PHY_RESET();
|
||||
#else
|
||||
/* PHY soft reset procedure.*/
|
||||
mii_write(ÐD0, MII_BMCR, BMCR_RESET);
|
||||
#if defined(BOARD_PHY_RESET_DELAY)
|
||||
osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
|
||||
#endif
|
||||
while (mii_read(ÐD0, MII_BMCR) & BMCR_RESET)
|
||||
;
|
||||
#endif
|
||||
|
||||
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||
/* PHY in power down mode until the driver will be started.*/
|
||||
mii_write(ÐD0, MII_BMCR, mii_read(ÐD0, MII_BMCR) | BMCR_PDOWN);
|
||||
#endif
|
||||
|
||||
/* MAC clocks stopped again. */
|
||||
pmcDisableETH0();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the MAC peripheral.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_start(MACDriver *macp) {
|
||||
unsigned i;
|
||||
|
||||
/* Disable interrupts */
|
||||
GMAC0->GMAC_IDR = 0xFFFFFFFF; /* Queue 0 */
|
||||
GMAC0->GMAC_IDRPQ[0] = 0xFFFFFFFF; /* Queue 1 */
|
||||
GMAC0->GMAC_IDRPQ[1] = 0xFFFFFFFF; /* Queue 2 */
|
||||
|
||||
/* Clear statistic */
|
||||
GMAC0->GMAC_NCR |= GMAC_NCR_CLRSTAT;
|
||||
|
||||
/* Clear rx and tx status bit */
|
||||
GMAC0->GMAC_RSR = 0xF;
|
||||
GMAC0->GMAC_TSR = 0xFF;
|
||||
|
||||
/* Clear interrupt status register */
|
||||
GMAC0->GMAC_ISR; /* Queue 0 */
|
||||
GMAC0->GMAC_ISRPQ[0]; /* Queue 1 */
|
||||
GMAC0->GMAC_ISRPQ[1]; /* Queue 2 */
|
||||
|
||||
/* Free all descriptors.*/
|
||||
for (i = 0; i < SAMA_MAC_RECEIVE_BUFFERS; i++)
|
||||
__eth_rd[i].rdes0 &= ~SAMA_RDES0_OWN;
|
||||
|
||||
/* Current receive descriptor */
|
||||
macp->rxptr = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||
|
||||
for (i = 0; i < SAMA_MAC_TRANSMIT_BUFFERS; i++)
|
||||
__eth_td[i].tdes1 |= SAMA_TDES1_LAST_BUFF | SAMA_TDES1_USED;
|
||||
|
||||
__eth_td1[0].tdes1 |= SAMA_TDES1_LAST_BUFF | SAMA_TDES1_USED;
|
||||
__eth_td2[0].tdes1 |= SAMA_TDES1_LAST_BUFF | SAMA_TDES1_USED;
|
||||
|
||||
macp->txptr = (sama_eth_tx_descriptor_t *)__eth_td;
|
||||
|
||||
/* MAC clocks activation and commanded reset procedure.*/
|
||||
pmcEnableETH0();
|
||||
|
||||
/* Enable interrupt */
|
||||
aicSetSourcePriority(ID_GMAC0, SAMA_MAC_ETH0_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_GMAC0, SAMA_ETH_HANDLER);
|
||||
aicEnableInt(ID_GMAC0);
|
||||
|
||||
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||
/* PHY in power up mode.*/
|
||||
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN);
|
||||
#endif
|
||||
|
||||
/* MAC address setup.*/
|
||||
if (macp->config->mac_address == NULL)
|
||||
mac_lld_set_address(default_mac_address);
|
||||
else
|
||||
mac_lld_set_address(macp->config->mac_address);
|
||||
|
||||
/* Transmitter and receiver enabled.
|
||||
Note that the complete setup of the MAC is performed when the link
|
||||
status is detected.*/
|
||||
uint32_t ncfgr = GMAC0->GMAC_NCFGR;
|
||||
|
||||
#if SAMA_MAC_IP_CHECKSUM_OFFLOAD
|
||||
GMAC0->GMAC_NCFGR = GMAC_NCFGR_SPD | GMAC_NCFGR_FD | GMAC_NCFGR_RXCOEN |
|
||||
GMAC_NCFGR_MAXFS | GMAC_NCFGR_RFCS | ncfgr;
|
||||
GMAC0->GMAC_DCFGR |= GMAC_DCFGR_TXCOEN;
|
||||
#else
|
||||
GMAC0->GMAC_NCFGR = GMAC_NCFGR_SPD | GMAC_NCFGR_FD |
|
||||
GMAC_NCFGR_MAXFS | GMAC_NCFGR_RFCS| ncfgr;
|
||||
#endif
|
||||
|
||||
/* DMA configuration:
|
||||
* Descriptor chains pointers.
|
||||
*/
|
||||
GMAC0->GMAC_RBQB = (uint32_t)__eth_rd;
|
||||
/*
|
||||
* The queue pointers must be initialized and point to
|
||||
* USED descriptor for all queues including those not
|
||||
* intended for use.
|
||||
*/
|
||||
GMAC0->GMAC_RBQBAPQ[0] = (uint32_t)__eth_rd;
|
||||
GMAC0->GMAC_RBQBAPQ[1] = (uint32_t)__eth_rd;
|
||||
|
||||
GMAC0->GMAC_TBQB = (uint32_t)__eth_td;
|
||||
/*
|
||||
* The queue pointers must be initialized and point to
|
||||
* USED descriptor for alla queues including those not
|
||||
* intended for use.
|
||||
*/
|
||||
GMAC0->GMAC_TBQBAPQ[0] = (uint32_t)__eth_td1;
|
||||
GMAC0->GMAC_TBQBAPQ[1] = (uint32_t)__eth_td2;
|
||||
|
||||
/* Enabling required interrupt sources.*/
|
||||
GMAC0->GMAC_IER = GMAC_IER_TCOMP | GMAC_IER_RCOMP;
|
||||
|
||||
/* DMA general settings.*/
|
||||
uint32_t dcfgr = GMAC0->GMAC_DCFGR & 0xFFFF;
|
||||
GMAC0->GMAC_DCFGR = dcfgr | GMAC_DCFGR_DRBS(24);
|
||||
|
||||
/* Enable RX and TX.*/
|
||||
GMAC0->GMAC_NCR |= GMAC_NCR_RXEN | GMAC_NCR_TXEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the MAC peripheral.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_stop(MACDriver *macp) {
|
||||
|
||||
if (macp->state != MAC_STOP) {
|
||||
#if SAMA_MAC_ETH0_CHANGE_PHY_STATE
|
||||
/* PHY in power down mode until the driver will be restarted.*/
|
||||
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN);
|
||||
#endif
|
||||
|
||||
/* Reset Network Control Register */
|
||||
GMAC0->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
|
||||
|
||||
/* Disable interrupts */
|
||||
GMAC0->GMAC_IDR = 0xFFFFFFFF;
|
||||
|
||||
/* Clear statistic */
|
||||
GMAC0->GMAC_NCR |= GMAC_NCR_CLRSTAT;
|
||||
|
||||
/* Clear rx and tx status bit */
|
||||
GMAC0->GMAC_RSR = 0xF;
|
||||
GMAC0->GMAC_TSR = 0xFF;
|
||||
|
||||
/* Clear interrupt status register */
|
||||
GMAC0->GMAC_ISR;
|
||||
|
||||
/* MAC clocks stopped.*/
|
||||
pmcDisableETH0();
|
||||
|
||||
/* ISR vector disabled.*/
|
||||
aicDisableInt(ID_GMAC0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a transmission descriptor.
|
||||
* @details One of the available transmission descriptors is locked and
|
||||
* returned.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[out] tdp pointer to a @p MACTransmitDescriptor structure
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK the descriptor has been obtained.
|
||||
* @retval MSG_TIMEOUT descriptor not available.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||
MACTransmitDescriptor *tdp) {
|
||||
sama_eth_tx_descriptor_t *tdes;
|
||||
|
||||
if (!macp->link_up)
|
||||
return MSG_TIMEOUT;
|
||||
|
||||
osalSysLock();
|
||||
|
||||
/* Get Current TX descriptor.*/
|
||||
tdes = macp->txptr;
|
||||
|
||||
/* Ensure that descriptor isn't owned by the Ethernet DMA or locked by
|
||||
another thread.*/
|
||||
if ((tdes->tdes1 & SAMA_TDES1_LOCKED) | (!(tdes->tdes1 & SAMA_TDES1_USED))) {
|
||||
osalSysUnlock();
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Marks the current descriptor as locked using a reserved bit.*/
|
||||
tdes->tdes1 |= SAMA_TDES1_LOCKED;
|
||||
|
||||
if (!(tdes->tdes1 & SAMA_TDES1_WRAP)) {
|
||||
macp->txptr += 1;
|
||||
}
|
||||
else {
|
||||
macp->txptr = (sama_eth_tx_descriptor_t *)__eth_td;
|
||||
}
|
||||
|
||||
osalSysUnlock();
|
||||
|
||||
/* Set the buffer size and configuration.*/
|
||||
tdp->offset = 0;
|
||||
tdp->size = SAMA_MAC_BUFFERS_SIZE;
|
||||
tdp->physdesc = tdes;
|
||||
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a transmit descriptor and starts the transmission of the
|
||||
* enqueued data as a single frame.
|
||||
*
|
||||
* @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
|
||||
|
||||
osalDbgAssert(tdp->physdesc->tdes1 & SAMA_TDES1_USED,
|
||||
"attempt to release descriptor already owned by DMA");
|
||||
|
||||
osalSysLock();
|
||||
|
||||
/* Unlocks the descriptor and returns it to the DMA engine.*/
|
||||
tdp->physdesc->tdes1 &= ~(SAMA_TDES1_LOCKED | SAMA_TDES1_USED | SAMA_TDES1_LENGTH_BUFF);
|
||||
/* Configure lentgh of buffer */
|
||||
tdp->physdesc->tdes1 |= (SAMA_TDES1_LENGTH_BUFF & tdp->offset);
|
||||
|
||||
/* Wait for the write to tdes1 to go through before resuming the DMA.*/
|
||||
__DSB();
|
||||
|
||||
if (!(GMAC0->GMAC_TSR & GMAC_TSR_TXGO)) {
|
||||
GMAC0->GMAC_NCR |= GMAC_NCR_TSTART;
|
||||
}
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a receive descriptor.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @param[out] rdp pointer to a @p MACReceiveDescriptor structure
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK the descriptor has been obtained.
|
||||
* @retval MSG_TIMEOUT descriptor not available.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||
MACReceiveDescriptor *rdp) {
|
||||
sama_eth_rx_descriptor_t *rdes;
|
||||
|
||||
osalSysLock();
|
||||
|
||||
/* Get Current RX descriptor.*/
|
||||
rdes = macp->rxptr;
|
||||
|
||||
/* Iterates through received frames until a valid one is found, invalid
|
||||
frames are discarded.*/
|
||||
while (rdes->rdes0 & SAMA_RDES0_OWN) {
|
||||
if (rdes->rdes1 & (SAMA_RDES1_EOF | SAMA_RDES1_SOF)) {
|
||||
/* Found a valid one.*/
|
||||
rdp->offset = 0;
|
||||
/* Only with RFCS set */
|
||||
rdp->size = (rdes->rdes1 & SAMA_RDES1_LOF);
|
||||
rdp->physdesc = rdes;
|
||||
if (!(rdes->rdes0 & SAMA_RDES0_WRAP)) {
|
||||
macp->rxptr += 1;
|
||||
}
|
||||
else {
|
||||
macp->rxptr = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||
}
|
||||
osalSysUnlock();
|
||||
return MSG_OK;
|
||||
}
|
||||
/* Invalid frame found, purging.*/
|
||||
rdes->rdes0 &= ~SAMA_RDES0_OWN;
|
||||
if (!(rdes->rdes0 & SAMA_RDES0_WRAP)) {
|
||||
rdes += 1;
|
||||
}
|
||||
else {
|
||||
rdes = (sama_eth_rx_descriptor_t *)__eth_rd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next descriptor to check.*/
|
||||
macp->rxptr = rdes;
|
||||
|
||||
osalSysUnlock();
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a receive descriptor.
|
||||
* @details The descriptor and its buffer are made available for more incoming
|
||||
* frames.
|
||||
*
|
||||
* @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
|
||||
|
||||
osalDbgAssert(rdp->physdesc->rdes0 & SAMA_RDES0_OWN,
|
||||
"attempt to release descriptor not owned by DMA");
|
||||
|
||||
osalSysLock();
|
||||
|
||||
/* Give buffer back to the Ethernet DMA.*/
|
||||
rdp->physdesc->rdes0 &= ~SAMA_RDES0_OWN;
|
||||
|
||||
/* Wait for the write to rdes0 to go through before resuming the DMA.*/
|
||||
__DSB();
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates and returns the link status.
|
||||
*
|
||||
* @param[in] macp pointer to the @p MACDriver object
|
||||
* @return The link status.
|
||||
* @retval true if the link is active.
|
||||
* @retval false if the link is down.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
bool mac_lld_poll_link_status(MACDriver *macp) {
|
||||
uint32_t maccr, bmsr, bmcr;
|
||||
|
||||
maccr = GMAC0->GMAC_NCFGR;
|
||||
|
||||
/* PHY CR and SR registers read.*/
|
||||
(void)mii_read(macp, MII_BMSR);
|
||||
bmsr = mii_read(macp, MII_BMSR);
|
||||
bmcr = mii_read(macp, MII_BMCR);
|
||||
|
||||
/* Check on auto-negotiation mode.*/
|
||||
if (bmcr & BMCR_ANENABLE) {
|
||||
uint32_t lpa;
|
||||
|
||||
/* Auto-negotiation must be finished without faults and link established.*/
|
||||
if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) !=
|
||||
(BMSR_LSTATUS | BMSR_ANEGCOMPLETE))
|
||||
return macp->link_up = false;
|
||||
|
||||
/* Auto-negotiation enabled, checks the LPA register.*/
|
||||
lpa = mii_read(macp, MII_LPA);
|
||||
|
||||
/* Check on link speed.*/
|
||||
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
|
||||
maccr |= GMAC_NCFGR_SPD;
|
||||
else
|
||||
maccr &= ~GMAC_NCFGR_SPD;
|
||||
|
||||
/* Check on link mode.*/
|
||||
if (lpa & (LPA_10FULL | LPA_100FULL))
|
||||
maccr |= GMAC_NCFGR_FD;
|
||||
else
|
||||
maccr &= ~GMAC_NCFGR_FD;
|
||||
}
|
||||
else {
|
||||
/* Link must be established.*/
|
||||
if (!(bmsr & BMSR_LSTATUS))
|
||||
return macp->link_up = false;
|
||||
|
||||
/* Check on link speed.*/
|
||||
if (bmcr & BMCR_SPEED100)
|
||||
maccr |= GMAC_NCFGR_SPD;
|
||||
else
|
||||
maccr &= ~GMAC_NCFGR_SPD;
|
||||
|
||||
/* Check on link mode.*/
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
maccr |= GMAC_NCFGR_FD;
|
||||
else
|
||||
maccr &= ~GMAC_NCFGR_FD;
|
||||
}
|
||||
|
||||
/* Changes the mode in the MAC.*/
|
||||
GMAC0->GMAC_NCFGR = maccr;
|
||||
|
||||
/* Returns the link status.*/
|
||||
return macp->link_up = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes to a transmit descriptor's stream.
|
||||
*
|
||||
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
|
||||
* @param[in] buf pointer to the buffer containing the data to be
|
||||
* written
|
||||
* @param[in] size number of bytes to be written
|
||||
* @return The number of bytes written into the descriptor's
|
||||
* stream, this value can be less than the amount
|
||||
* specified in the parameter @p size if the maximum
|
||||
* frame size is reached.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||
uint8_t *buf,
|
||||
size_t size) {
|
||||
|
||||
osalDbgAssert((tdp->physdesc->tdes1 & SAMA_TDES1_USED),
|
||||
"attempt to write descriptor not owned");
|
||||
|
||||
if (size > tdp->size - tdp->offset)
|
||||
size = tdp->size - tdp->offset;
|
||||
|
||||
if (size > 0) {
|
||||
memcpy((uint8_t *)(tdp->physdesc->tdes0) + tdp->offset, buf, size);
|
||||
tdp->offset += size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads from a receive descriptor's stream.
|
||||
*
|
||||
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
|
||||
* @param[in] buf pointer to the buffer that will receive the read data
|
||||
* @param[in] size number of bytes to be read
|
||||
* @return The number of bytes read from the descriptor's
|
||||
* stream, this value can be less than the amount
|
||||
* specified in the parameter @p size if there are
|
||||
* no more bytes to read.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||
uint8_t *buf,
|
||||
size_t size) {
|
||||
|
||||
osalDbgAssert((rdp->physdesc->rdes0 & SAMA_RDES0_OWN),
|
||||
"attempt to read descriptor not owned");
|
||||
|
||||
if (size > rdp->size - rdp->offset)
|
||||
size = rdp->size - rdp->offset;
|
||||
|
||||
if (size > 0) {
|
||||
memcpy(buf, (uint8_t *)(rdp->physdesc->rdes0 & SAMA_RDES0_RBAP_MASK) + rdp->offset, size);
|
||||
rdp->offset += size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Returns a pointer to the next transmit buffer in the descriptor
|
||||
* chain.
|
||||
* @note The API guarantees that enough buffers can be requested to fill
|
||||
* a whole frame.
|
||||
*
|
||||
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
|
||||
* @param[in] size size of the requested buffer. Specify the frame size
|
||||
* on the first call then scale the value down subtracting
|
||||
* the amount of data already copied into the previous
|
||||
* buffers.
|
||||
* @param[out] sizep pointer to variable receiving the buffer size, it is
|
||||
* zero when the last buffer has already been returned.
|
||||
* Note that a returned size lower than the amount
|
||||
* requested means that more buffers must be requested
|
||||
* in order to fill the frame data entirely.
|
||||
* @return Pointer to the returned buffer.
|
||||
* @retval NULL if the buffer chain has been entirely scanned.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
|
||||
size_t size,
|
||||
size_t *sizep) {
|
||||
|
||||
if (tdp->offset == 0) {
|
||||
*sizep = tdp->size;
|
||||
tdp->offset = size;
|
||||
return (uint8_t *)tdp->physdesc->tdes0;
|
||||
}
|
||||
*sizep = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the next receive buffer in the descriptor
|
||||
* chain.
|
||||
* @note The API guarantees that the descriptor chain contains a whole
|
||||
* frame.
|
||||
*
|
||||
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
|
||||
* @param[out] sizep pointer to variable receiving the buffer size, it is
|
||||
* zero when the last buffer has already been returned.
|
||||
* @return Pointer to the returned buffer.
|
||||
* @retval NULL if the buffer chain has been entirely scanned.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
|
||||
size_t *sizep) {
|
||||
|
||||
if (rdp->size > 0) {
|
||||
*sizep = rdp->size;
|
||||
rdp->offset = rdp->size;
|
||||
rdp->size = 0;
|
||||
return (uint8_t *)rdp->physdesc->rdes0 & SAMA_RDES0_RBAP_MASK;
|
||||
}
|
||||
*sizep = 0;
|
||||
return NULL;
|
||||
}
|
||||
#endif /* MAC_USE_ZERO_COPY */
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
/** @} */
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MACv1/hal_mac_lld.h
|
||||
* @brief SAMA low level MAC driver header.
|
||||
*
|
||||
* @addtogroup MAC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_MAC_LLD_H
|
||||
#define HAL_MAC_LLD_H
|
||||
|
||||
#if HAL_USE_MAC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief This implementation supports the zero-copy mode API.
|
||||
*/
|
||||
#define MAC_SUPPORTS_ZERO_COPY FALSE
|
||||
|
||||
/**
|
||||
* @name RDES0 constants
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_RDES0_RBAP_MASK 0xFFFFFFFC
|
||||
#define SAMA_RDES0_WRAP 0x00000002
|
||||
#define SAMA_RDES0_OWN 0x00000001
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name RDES1 constants
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_RDES1_BROADCAST 0x80000000
|
||||
#define SAMA_RDES1_MULTICAST_HASH 0x40000000
|
||||
#define SAMA_RDES1_UNICAST_HASH 0x20000000
|
||||
#define SAMA_RDES1_ADDR_REG_MATCH 0x08000000
|
||||
#define SAMA_RDES1_ADDR_REG 0x06000000
|
||||
#define SAMA_RDES1_ID_REG_MATCH 0x01000000
|
||||
#define SAMA_RDES1_SNAP_ENCODED 0x01000000
|
||||
#define SAMA_RDES1_ID_REG 0x00C00000
|
||||
#define SAMA_RDES1_CHECKSUM_IP_TCP 0x00800000
|
||||
#define SAMA_RDES1_CHECKSUM_IP_UDP 0x00C00000
|
||||
#define SAMA_RDES1_CHECKSUM_IP 0x00400000
|
||||
#define SAMA_RDES1_VLAN_TAG_DET 0x00200000
|
||||
#define SAMA_RDES1_PRIOR_TAG_DET 0x00100000
|
||||
#define SAMA_RDES1_VLAN_PRIOR 0x000E0000
|
||||
#define SAMA_RDES1_CFI 0x00010000
|
||||
#define SAMA_RDES1_EOF 0x00008000
|
||||
#define SAMA_RDES1_SOF 0x00004000
|
||||
#define SAMA_RDES1_ADD_BIT_LOF 0x00002000
|
||||
#define SAMA_RDES1_BAD_FCS 0x00002000
|
||||
#define SAMA_RDES1_LOF 0x00001FFF
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name TDES0 constants
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_TDES0_BYTE_ADDR 0xFFFFFFFF
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name TDES1 constants
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_TDES1_USED 0x80000000
|
||||
#define SAMA_TDES1_WRAP 0x40000000
|
||||
#define SAMA_TDES1_RLE_TX_ERR 0x20000000
|
||||
#define SAMA_TDES1_LOCKED 0x10000000 /* NOTE: Pseudo flag. */
|
||||
#define SAMA_TDES1_AHB_TX_ERR 0x08000000
|
||||
#define SAMA_TDES1_LC_TX_ERR 0x04000000
|
||||
#define SAMA_TDES1_CHECKSUM_ERR 0x00700000
|
||||
#define SAMA_TDES1_CRC 0x00010000
|
||||
#define SAMA_TDES1_LAST_BUFF 0x00008000
|
||||
#define SAMA_TDES1_LENGTH_BUFF 0x00003FFF
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Number of available transmit buffers.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_TRANSMIT_BUFFERS 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of available receive buffers.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_RECEIVE_BUFFERS 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum supported frame size.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_BUFFERS_SIZE 1536
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PHY detection timeout.
|
||||
* @details Timeout for PHY address detection, the scan for a PHY is performed
|
||||
* the specified number of times before invoking the failure handler.
|
||||
* This setting applies only if the PHY address is not explicitly
|
||||
* set in the board header file using @p BOARD_PHY_ADDRESS. A zero
|
||||
* value disables the timeout and a single search is performed.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_PHY_TIMEOUT 100
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Change the PHY power state inside the driver.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_ETH0_CHANGE_PHY_STATE) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_ETH0_CHANGE_PHY_STATE TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ETHD0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_ETH0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_ETH0_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IP checksum offload.
|
||||
* @details The following modes are available:
|
||||
* - 0 Function disabled.
|
||||
* - 1 IP/TCP/UDP header checksum calculation and insertion are enabled.
|
||||
*/
|
||||
#if !defined(SAMA_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__)
|
||||
#define SAMA_MAC_IP_CHECKSUM_OFFLOAD 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of an SAMA Ethernet receive descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
volatile uint32_t rdes0;
|
||||
volatile uint32_t rdes1;
|
||||
} sama_eth_rx_descriptor_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an SAMA Ethernet transmit descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
volatile uint32_t tdes0;
|
||||
volatile uint32_t tdes1;
|
||||
} sama_eth_tx_descriptor_t;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief MAC address.
|
||||
*/
|
||||
uint8_t *mac_address;
|
||||
/* End of the mandatory fields.*/
|
||||
} MACConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a MAC driver.
|
||||
*/
|
||||
struct MACDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
macstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const MACConfig *config;
|
||||
/**
|
||||
* @brief Transmit semaphore.
|
||||
*/
|
||||
threads_queue_t tdqueue;
|
||||
/**
|
||||
* @brief Receive semaphore.
|
||||
*/
|
||||
threads_queue_t rdqueue;
|
||||
#if MAC_USE_EVENTS || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Receive event.
|
||||
*/
|
||||
event_source_t rdevent;
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Link status flag.
|
||||
*/
|
||||
bool link_up;
|
||||
/**
|
||||
* @brief PHY address (pre shifted).
|
||||
*/
|
||||
uint32_t phyaddr;
|
||||
/**
|
||||
* @brief Receive next frame pointer.
|
||||
*/
|
||||
sama_eth_rx_descriptor_t *rxptr;
|
||||
/**
|
||||
* @brief Transmit next frame pointer.
|
||||
*/
|
||||
sama_eth_tx_descriptor_t *txptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure representing a transmit descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Current write offset.
|
||||
*/
|
||||
size_t offset;
|
||||
/**
|
||||
* @brief Available space size.
|
||||
*/
|
||||
size_t size;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the physical descriptor.
|
||||
*/
|
||||
sama_eth_tx_descriptor_t *physdesc;
|
||||
} MACTransmitDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a receive descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Current read offset.
|
||||
*/
|
||||
size_t offset;
|
||||
/**
|
||||
* @brief Available data size.
|
||||
*/
|
||||
size_t size;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the physical descriptor.
|
||||
*/
|
||||
sama_eth_rx_descriptor_t *physdesc;
|
||||
} MACReceiveDescriptor;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern MACDriver ETHD0;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void mii_write(MACDriver *macp, uint32_t reg, uint32_t value);
|
||||
uint32_t mii_read(MACDriver *macp, uint32_t reg);
|
||||
void mac_lld_init(void);
|
||||
void mac_lld_start(MACDriver *macp);
|
||||
void mac_lld_stop(MACDriver *macp);
|
||||
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
|
||||
MACTransmitDescriptor *tdp);
|
||||
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
|
||||
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
|
||||
MACReceiveDescriptor *rdp);
|
||||
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
|
||||
bool mac_lld_poll_link_status(MACDriver *macp);
|
||||
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
|
||||
uint8_t *buf,
|
||||
size_t size);
|
||||
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
|
||||
uint8_t *buf,
|
||||
size_t size);
|
||||
#if MAC_USE_ZERO_COPY
|
||||
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
|
||||
size_t size,
|
||||
size_t *sizep);
|
||||
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
|
||||
size_t *sizep);
|
||||
#endif /* MAC_USE_ZERO_COPY */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_MAC */
|
||||
|
||||
#endif /* HAL_MAC_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/PIOv1
|
|
@ -1,387 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file PIOv1/hal_pal_lld.c
|
||||
* @brief SAMA PAL low level driver code.
|
||||
*
|
||||
* @addtogroup PAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
#define __PIOA ((Pio *)0xFC038000U)
|
||||
|
||||
#define EVENTS_NUMBER (4 * 32)
|
||||
|
||||
/**
|
||||
* @brief PIOA interrupt priority level setting.
|
||||
*/
|
||||
#define SAMA_PIOA_IRQ_PRIORITY 2
|
||||
|
||||
/**
|
||||
* @brief PIOB interrupt priority level setting.
|
||||
*/
|
||||
#define SAMA_PIOB_IRQ_PRIORITY 2
|
||||
|
||||
/**
|
||||
* @brief PIOC interrupt priority level setting.
|
||||
*/
|
||||
#define SAMA_PIOC_IRQ_PRIORITY 2
|
||||
|
||||
/**
|
||||
* @brief PIOD interrupt priority level setting.
|
||||
*/
|
||||
#define SAMA_PIOD_IRQ_PRIORITY 2
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Event records for the GPIO interrupts.
|
||||
*/
|
||||
palevent_t _pal_events[EVENTS_NUMBER];
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief PIOA interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_PIOA_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr, imr, is;
|
||||
uint8_t i, j;
|
||||
|
||||
sr = pal_lld_read_status(PIOA);
|
||||
imr = pal_lld_read_int_mask(PIOA);
|
||||
|
||||
is = sr & imr;
|
||||
for (j = 0, i = 0; i < 32; i++, j++) {
|
||||
if (!(is & (0x1 << j))) {
|
||||
continue;
|
||||
}
|
||||
#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
|
||||
if (_pal_events[i].cb != NULL) {
|
||||
_pal_events[i].cb(&is);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PIOB interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_PIOB_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr, imr, is;
|
||||
uint8_t i, j;
|
||||
|
||||
sr = pal_lld_read_status(PIOB);
|
||||
imr = pal_lld_read_int_mask(PIOB);
|
||||
|
||||
is = sr & imr;
|
||||
for (j = 0, i = 32; i < 64; i++, j++) {
|
||||
if (!(is & (0x1 << j))) {
|
||||
continue;
|
||||
}
|
||||
#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
|
||||
if (_pal_events[i].cb != NULL) {
|
||||
_pal_events[i].cb(&is);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PIOC interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_PIOC_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr, imr, is;
|
||||
uint8_t i, j;
|
||||
|
||||
sr = pal_lld_read_status(PIOC);
|
||||
imr = pal_lld_read_int_mask(PIOC);
|
||||
|
||||
is = sr & imr;
|
||||
for (j = 0, i = 64; i < 96; i++, j++) {
|
||||
if (!(is & (0x1 << j))) {
|
||||
continue;
|
||||
}
|
||||
#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
|
||||
if (_pal_events[i].cb != NULL) {
|
||||
_pal_events[i].cb(&is);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PIOD interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_PIOD_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr, imr, is;
|
||||
uint8_t i, j;
|
||||
|
||||
sr = pal_lld_read_status(PIOD);
|
||||
imr = pal_lld_read_int_mask(PIOD);
|
||||
|
||||
is = sr & imr;
|
||||
for (j = 0, i = 96; i < 128; i++, j++) {
|
||||
if (!(is & (0x1 << j))) {
|
||||
continue;
|
||||
}
|
||||
#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__)
|
||||
if (_pal_events[i].cb != NULL) {
|
||||
_pal_events[i].cb(&is);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief PAL driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_init(void) {
|
||||
|
||||
#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < EVENTS_NUMBER; i++) {
|
||||
_pal_init_event(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears status register
|
||||
*/
|
||||
pal_lld_read_status(PIOA);
|
||||
pal_lld_read_status(PIOB);
|
||||
pal_lld_read_status(PIOC);
|
||||
pal_lld_read_status(PIOD);
|
||||
|
||||
aicSetSourcePriority(ID_PIOA, SAMA_PIOA_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_PIOA, SAMA_PIOA_HANDLER);
|
||||
aicEnableInt(ID_PIOA);
|
||||
|
||||
aicSetSourcePriority(ID_PIOB, SAMA_PIOB_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_PIOB, SAMA_PIOB_HANDLER);
|
||||
aicEnableInt(ID_PIOB);
|
||||
|
||||
aicSetSourcePriority(ID_PIOC, SAMA_PIOC_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_PIOC, SAMA_PIOC_HANDLER);
|
||||
aicEnableInt(ID_PIOC);
|
||||
|
||||
aicSetSourcePriority(ID_PIOD, SAMA_PIOD_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_PIOD, SAMA_PIOD_HANDLER);
|
||||
aicEnableInt(ID_PIOD);
|
||||
#endif /* #if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pads mode setup.
|
||||
* @details This function programs a pads group belonging to the same port
|
||||
* with the specified mode.
|
||||
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum
|
||||
* speed.
|
||||
*
|
||||
* @param[in] port the port identifier
|
||||
* @param[in] mask the group mask
|
||||
* @param[in] mode the mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_setgroupmode(ioportid_t port,
|
||||
ioportmask_t mask,
|
||||
iomode_t mode) {
|
||||
|
||||
uint32_t mskr = (mask);
|
||||
uint32_t cfgr = (mode & (PAL_SAMA_CFGR_MASK));
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
if(mode && PAL_SAMA_SECURE_MASK) {
|
||||
port->SIOSR = mask;
|
||||
}
|
||||
else {
|
||||
port->SIONR = mask;
|
||||
}
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
port->MSKR = mskr;
|
||||
port->CFGR = cfgr;
|
||||
}
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
/**
|
||||
* @brief Configures debouncing time for pads.
|
||||
*
|
||||
* @param[in] db_time debouncing time
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void pal_lld_cfg_debouncing_time(uint32_t db_time) {
|
||||
|
||||
/*
|
||||
* Debouncing time configuration only in SECURE STATE
|
||||
*/
|
||||
__PIOA->S_PIO_SCDR = db_time & 0x3FFF;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reads/Clears Interrupt Status Register.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint32_t pal_lld_read_status(ioportid_t port) {
|
||||
return port->ISR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads Interrupt Mask Register.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint32_t pal_lld_read_int_mask(ioportid_t port) {
|
||||
return port->IMR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads Configuration Register.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint32_t pal_lld_read_cfgr(ioportid_t port) {
|
||||
return port->CFGR;
|
||||
}
|
||||
|
||||
#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Pad event enable.
|
||||
* @note Programming an unknown or unsupported mode is silently ignored.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
* @param[in] mode pad event mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_enablepadevent(ioportid_t port,
|
||||
iopadid_t pad,
|
||||
ioeventmode_t mode) {
|
||||
|
||||
port->MSKR = pad;
|
||||
port->CFGR |= mode;
|
||||
port->IER = pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a PAL event structure associated to a pad.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
palevent_t* pal_lld_get_pad_event(ioportid_t port, iopadid_t pad) {
|
||||
|
||||
palevent_t* palevt = NULL;
|
||||
|
||||
if (port == PIOA) {
|
||||
palevt = &_pal_events[pad];
|
||||
}
|
||||
else if (port == PIOB) {
|
||||
palevt = &_pal_events[32 + pad];
|
||||
}
|
||||
else if (port == PIOC) {
|
||||
palevt = &_pal_events[64 + pad];
|
||||
}
|
||||
else {
|
||||
palevt = &_pal_events[96 + pad];
|
||||
}
|
||||
|
||||
return palevt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pad event disable.
|
||||
* @details This function disables previously programmed event callbacks.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) {
|
||||
|
||||
port->IDR |= pad;
|
||||
|
||||
#if PAL_USE_CALLBACKS || PAL_USE_WAIT
|
||||
/* Callback cleared and/or thread reset.*/
|
||||
_pal_clear_event(pad);
|
||||
#endif
|
||||
}
|
||||
#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
/** @} */
|
|
@ -1,559 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file PIOv1/hal_pal_lld.h
|
||||
* @brief SAMA PAL low level driver header.
|
||||
*
|
||||
* @addtogroup PAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_PAL_LLD_H
|
||||
#define HAL_PAL_LLD_H
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Unsupported modes and specific modes */
|
||||
/*===========================================================================*/
|
||||
/* Specifies palInit() without parameter, required until all platforms will
|
||||
be updated to the new style.*/
|
||||
#define PAL_NEW_INIT
|
||||
|
||||
#undef PAL_MODE_RESET
|
||||
#undef PAL_MODE_UNCONNECTED
|
||||
#undef PAL_MODE_INPUT
|
||||
#undef PAL_MODE_INPUT_PULLUP
|
||||
#undef PAL_MODE_INPUT_PULLDOWN
|
||||
#undef PAL_MODE_INPUT_ANALOG
|
||||
#undef PAL_MODE_OUTPUT_PUSHPULL
|
||||
#undef PAL_MODE_OUTPUT_OPENDRAIN
|
||||
|
||||
/**
|
||||
* @name SAMA-specific I/O mode flags
|
||||
* @{
|
||||
*/
|
||||
#define PAL_SAMA_FUNC_MASK (7U << 0U)
|
||||
#define PAL_SAMA_FUNC_GPIO (0U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_A (1U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_B (2U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_C (3U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_D (4U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_E (5U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_F (6U << 0U)
|
||||
#define PAL_SAMA_FUNC_PERIPH_G (7U << 0U)
|
||||
|
||||
#define PAL_SAMA_DIR_MASK (1U << 8U)
|
||||
#define PAL_SAMA_DIR_INPUT (0U << 8U)
|
||||
#define PAL_SAMA_DIR_OUTPUT (1U << 8U)
|
||||
|
||||
#define PAL_SAMA_PUEN_MASK (1U << 9U)
|
||||
#define PAL_SAMA_PUEN_PULLUP (1U << 9U)
|
||||
|
||||
#define PAL_SAMA_PDEN_MASK (1U << 10U)
|
||||
#define PAL_SAMA_PDEN_PULLDOWN (1U << 10U)
|
||||
|
||||
#define PAL_SAMA_IFEN_MASK (1U << 12U)
|
||||
#define PAL_SAMA_PDEN_INPUTFILTER (1U << 12U)
|
||||
|
||||
#define PAL_SAMA_IFSCEN_MASK (1U << 13U)
|
||||
#define PAL_SAMA_IFSCEN_MCK_2 (0U << 13U)
|
||||
#define PAL_SAMA_IFSCEN_SLCK_2 (1U << 13U)
|
||||
|
||||
#define PAL_SAMA_OPD_MASK (1U << 14U)
|
||||
#define PAL_SAMA_OPD_PUSHPULL (0U << 14U)
|
||||
#define PAL_SAMA_OPD_OPENDRAIN (1U << 14U)
|
||||
|
||||
#define PAL_SAMA_SCHMITT_MASK (1U << 15U)
|
||||
#define PAL_SAMA_SCHMITT (1U << 15U)
|
||||
|
||||
#define PAL_SAMA_DRVSTR_MASK (3U << 16U)
|
||||
#define PAL_SAMA_DRVSTR_LO (1U << 16U)
|
||||
#define PAL_SAMA_DRVSTR_ME (2U << 16U)
|
||||
#define PAL_SAMA_DRVSTR_HI (3U << 16U)
|
||||
|
||||
#define PAL_SAMA_EVTSEL_MASK (7U << 24U)
|
||||
#define PAL_SAMA_EVTSEL_FALLING (0U << 24U)
|
||||
#define PAL_SAMA_EVTSEL_RISING (1U << 24U)
|
||||
#define PAL_SAMA_EVTSEL_BOTH (2U << 24U)
|
||||
#define PAL_SAMA_EVTSEL_LOW (3U << 24U)
|
||||
#define PAL_SAMA_EVTSEL_HIGH (4U << 24U)
|
||||
|
||||
#define PAL_SAMA_PCFS_MASK (1U << 29U)
|
||||
#define PAL_SAMA_ICFS_MASK (1U << 30U)
|
||||
|
||||
|
||||
#define PAL_SAMA_CFGR_MASK PAL_SAMA_FUNC_MASK | \
|
||||
PAL_SAMA_DIR_MASK | \
|
||||
PAL_SAMA_PUEN_MASK | \
|
||||
PAL_SAMA_PDEN_MASK | \
|
||||
PAL_SAMA_IFEN_MASK | \
|
||||
PAL_SAMA_IFSCEN_MASK | \
|
||||
PAL_SAMA_OPD_MASK | \
|
||||
PAL_SAMA_SCHMITT_MASK | \
|
||||
PAL_SAMA_DRVSTR_MASK | \
|
||||
PAL_SAMA_EVTSEL_MASK
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PAL_SAMA_SECURE_MASK (1U << 31U)
|
||||
|
||||
#define PAL_SAMA_NON_SECURE (0U << 31U)
|
||||
#define PAL_SAMA_SECURE (1U << 31U)
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/**
|
||||
* @name Standard I/O mode flags
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Implemented as input.
|
||||
*/
|
||||
#define PAL_MODE_RESET (PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_SCHMITT)
|
||||
|
||||
/**
|
||||
* @brief Implemented as input with pull-up.
|
||||
*/
|
||||
#define PAL_MODE_UNCONNECTED (PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_SCHMITT | \
|
||||
PAL_SAMA_PUEN_PULLUP)
|
||||
|
||||
/**
|
||||
* @brief Regular input high-Z pad.
|
||||
*/
|
||||
#define PAL_MODE_INPUT (PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_SCHMITT)
|
||||
|
||||
/**
|
||||
* @brief Input pad with weak pull up resistor.
|
||||
*/
|
||||
#define PAL_MODE_INPUT_PULLUP (PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_SCHMITT | \
|
||||
PAL_SAMA_PUEN_PULLUP)
|
||||
|
||||
/**
|
||||
* @brief Input pad with weak pull down resistor.
|
||||
*/
|
||||
#define PAL_MODE_INPUT_PULLDOWN (PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_SCHMITT | \
|
||||
PAL_SAMA_PDEN_PULLDOWN)
|
||||
|
||||
/**
|
||||
* @brief Analog input mode.
|
||||
*/
|
||||
#define PAL_MODE_INPUT_ANALOG PAL_SAMA_DIR_INPUT
|
||||
|
||||
/**
|
||||
* @brief Push-pull output pad.
|
||||
*/
|
||||
#define PAL_MODE_OUTPUT_PUSHPULL PAL_SAMA_DIR_OUTPUT
|
||||
|
||||
/**
|
||||
* @brief Open-drain output pad.
|
||||
*/
|
||||
#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_SAMA_DIR_OUTPUT | \
|
||||
PAL_SAMA_OPD_OPENDRAIN)
|
||||
|
||||
#if SAMA_HAL_IS_SECURE || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Secure pad.
|
||||
* @note Available only on Secure HAL.
|
||||
*/
|
||||
#define PAL_MODE_SECURE PAL_SAMA_SECURE
|
||||
|
||||
/**
|
||||
* @brief Non secure pad.
|
||||
* @note Available only on Secure HAL.
|
||||
*/
|
||||
#define PAL_MODE_NON_SECURE PAL_SAMA_NON_SECURE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/* Discarded definitions from the Atmel headers, the PAL driver uses its own
|
||||
definitions in order to have an unified handling for all devices.
|
||||
Unfortunately the ST headers have no uniform definitions for the same
|
||||
objects across the various sub-families.*/
|
||||
#undef PIOA
|
||||
|
||||
/**
|
||||
* @name PIO ports definitions
|
||||
* @{
|
||||
*/
|
||||
#define PIOA ((sama_pio_t *)PIOA_BASE)
|
||||
#define PIOB ((sama_pio_t *)PIOB_BASE)
|
||||
#define PIOC ((sama_pio_t *)PIOC_BASE)
|
||||
#define PIOD ((sama_pio_t *)PIOD_BASE)
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Types and constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Port related definitions
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Width, in bits, of an I/O port.
|
||||
*/
|
||||
#define PAL_IOPORTS_WIDTH 32
|
||||
|
||||
/**
|
||||
* @brief Whole port mask.
|
||||
* @details This macro specifies all the valid bits into a port.
|
||||
*/
|
||||
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Line handling macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Forms a line identifier.
|
||||
* @details A port/pad pair are encoded into an @p ioline_t type. The encoding
|
||||
* of this type is platform-dependent.
|
||||
* @note In this driver the pad number is encoded in the lower 5 bits of
|
||||
* the PIO address which are guaranteed to be zero.
|
||||
*/
|
||||
#define PAL_LINE(port, pad) \
|
||||
((ioline_t)((uint32_t)(port)) | ((uint32_t)(pad)))
|
||||
|
||||
/**
|
||||
* @brief Decodes a port identifier from a line identifier.
|
||||
*/
|
||||
#define PAL_PORT(line) \
|
||||
((sama_pio_t *)(((uint32_t)(line)) & 0xFFFFFFE0U))
|
||||
|
||||
/**
|
||||
* @brief Decodes a pad identifier from a line identifier.
|
||||
*/
|
||||
#define PAL_PAD(line) \
|
||||
((uint32_t)((uint32_t)(line) & 0x0000001FU))
|
||||
|
||||
/**
|
||||
* @brief Value identifying an invalid line.
|
||||
*/
|
||||
#define PAL_NOLINE 0U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief SAMA PIO registers block.
|
||||
*/
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
typedef struct {
|
||||
volatile uint32_t MSKR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t PDSR;
|
||||
volatile uint32_t LOCKSR;
|
||||
volatile uint32_t SODR;
|
||||
volatile uint32_t CODR;
|
||||
volatile uint32_t ODSR;
|
||||
volatile uint32_t Reserved1;
|
||||
volatile uint32_t IER;
|
||||
volatile uint32_t IDR;
|
||||
volatile uint32_t IMR;
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t SIONR;
|
||||
volatile uint32_t SIOSR;
|
||||
volatile uint32_t IOSSR;
|
||||
volatile uint32_t IOFR;
|
||||
} sama_pio_t;
|
||||
#else
|
||||
typedef struct {
|
||||
volatile uint32_t MSKR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t PDSR;
|
||||
volatile uint32_t LOCKSR;
|
||||
volatile uint32_t SODR;
|
||||
volatile uint32_t CODR;
|
||||
volatile uint32_t ODSR;
|
||||
volatile uint32_t Reserved1;
|
||||
volatile uint32_t IER;
|
||||
volatile uint32_t IDR;
|
||||
volatile uint32_t IMR;
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t Reserved2[3];
|
||||
volatile uint32_t IOFR;
|
||||
} sama_pio_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SAMA PIO static initializer.
|
||||
* @details It is a dummy.
|
||||
*/
|
||||
typedef uint32_t PALConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of digital I/O port sized unsigned integer.
|
||||
*/
|
||||
typedef uint32_t ioportmask_t;
|
||||
|
||||
/**
|
||||
* @brief Type of digital I/O modes.
|
||||
*/
|
||||
typedef uint32_t iomode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an I/O line.
|
||||
*/
|
||||
typedef uint32_t ioline_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an event mode.
|
||||
*/
|
||||
typedef uint32_t ioeventmode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a port Identifier.
|
||||
* @details This type can be a scalar or some kind of pointer, do not make
|
||||
* any assumption about it, use the provided macros when populating
|
||||
* variables of this type.
|
||||
*/
|
||||
typedef sama_pio_t * ioportid_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an pad identifier.
|
||||
*/
|
||||
typedef uint32_t iopadid_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* I/O Ports Identifiers. */
|
||||
/* The low level driver wraps the definitions already present in the SAMA */
|
||||
/* firmware library. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief PIO port A identifier.
|
||||
*/
|
||||
#if SAMA_HAS_PIOA || defined(__DOXYGEN__)
|
||||
#define IOPORT1 PIOA
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PIO port B identifier.
|
||||
*/
|
||||
#if SAMA_HAS_PIOB || defined(__DOXYGEN__)
|
||||
#define IOPORT2 PIOB
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PIO port C identifier.
|
||||
*/
|
||||
#if SAMA_HAS_PIOC || defined(__DOXYGEN__)
|
||||
#define IOPORT3 PIOC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PIO port D identifier.
|
||||
*/
|
||||
#if SAMA_HAS_PIOD || defined(__DOXYGEN__)
|
||||
#define IOPORT4 PIOD
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Implementation, some of the following macros could be implemented as */
|
||||
/* functions, if so please put them in pal_lld.c. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief GPIO ports subsystem initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_init() _pal_lld_init()
|
||||
|
||||
/**
|
||||
* @brief Reads an I/O port.
|
||||
* @details This function is implemented by reading the PIO PDSR register, the
|
||||
* implementation has no side effects.
|
||||
* @note This function is not meant to be invoked directly by the application
|
||||
* code.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @return The port bits.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_readport(port) ((port)->PDSR)
|
||||
|
||||
/**
|
||||
* @brief Reads the output latch.
|
||||
* @details This function is implemented by reading the PIO ODSR register, the
|
||||
* implementation has no side effects.
|
||||
* @note This function is not meant to be invoked directly by the application
|
||||
* code.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @return The latched logical states.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_readlatch(port) ((port)->ODSR)
|
||||
|
||||
/**
|
||||
* @brief Writes on a I/O port.
|
||||
* @details This function is implemented by writing the PIO ODR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] bits bits to be written on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writeport(port, bits) \
|
||||
do { \
|
||||
(port)->MSKR = 0xFFFFFFFFU; \
|
||||
(port)->ODSR = (bits); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Sets a bits mask on a I/O port.
|
||||
* @details This function is implemented by writing the PIO BSRR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] bits bits to be ORed on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_setport(port, bits) ((port)->SODR = (bits))
|
||||
|
||||
/**
|
||||
* @brief Clears a bits mask on a I/O port.
|
||||
* @details This function is implemented by writing the PIO BSRR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] bits bits to be cleared on the specified port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_clearport(port, bits) ((port)->CODR = (bits))
|
||||
|
||||
/**
|
||||
* @brief Writes a group of bits.
|
||||
* @details This function is implemented by writing the PIO BSRR register, the
|
||||
* implementation has no side effects.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] mask group mask
|
||||
* @param[in] offset the group bit offset within the port
|
||||
* @param[in] bits bits to be written. Values exceeding the group
|
||||
* width are masked.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writegroup(port, mask, offset, bits) \
|
||||
do { \
|
||||
(port)->MSKR = ((mask) << (offset)); \
|
||||
(port)->ODSR = (((bits) & (mask)) << (offset)); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Pads group mode setup.
|
||||
* @details This function programs a pads group belonging to the same port
|
||||
* with the specified mode.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] mask group mask
|
||||
* @param[in] offset group bit offset within the port
|
||||
* @param[in] mode group mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_setgroupmode(port, mask, offset, mode) \
|
||||
_pal_lld_setgroupmode(port, mask << offset, mode)
|
||||
|
||||
/**
|
||||
* @brief Writes a logical state on an output pad.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
* @param[in] bit logical value, the value must be @p PAL_LOW or
|
||||
* @p PAL_HIGH
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
|
||||
|
||||
/**
|
||||
* @brief Pad event enable.
|
||||
* @note Programming an unknown or unsupported mode is silently ignored.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
* @param[in] mode pad event mode
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_enablepadevent(port, pad, mode) \
|
||||
_pal_lld_enablepadevent(port, pad, mode)
|
||||
|
||||
/**
|
||||
* @brief Pad event disable.
|
||||
* @details This function disables previously programmed event callbacks.
|
||||
*
|
||||
* @param[in] port port identifier
|
||||
* @param[in] pad pad number within the port
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_disablepadevent(port, pad) \
|
||||
_pal_lld_disablepadevent(port, pad)
|
||||
|
||||
/**
|
||||
* @brief Returns a PAL event structure associated to a line.
|
||||
*
|
||||
* @param[in] line line identifier
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define pal_lld_get_line_event(line) \
|
||||
&_pal_events[PAL_PAD(line)]
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern palevent_t _pal_events[4 * 32];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _pal_lld_init(void);
|
||||
void _pal_lld_setgroupmode(ioportid_t port,
|
||||
ioportmask_t mask,
|
||||
iomode_t mode);
|
||||
void _pal_lld_enablepadevent(ioportid_t port,
|
||||
iopadid_t pad,
|
||||
ioeventmode_t mode);
|
||||
void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad);
|
||||
palevent_t* pal_lld_get_pad_event(ioportid_t port, iopadid_t pad);
|
||||
/* LLD only functions */
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
void pal_lld_cfg_debouncing_time(uint32_t db_time);
|
||||
#endif
|
||||
uint32_t pal_lld_read_status(ioportid_t port);
|
||||
uint32_t pal_lld_read_int_mask(ioportid_t port);
|
||||
uint32_t pal_lld_read_cfgr(ioportid_t port);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
#endif /* HAL_PAL_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_TRNG TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_trng_lld.c
|
||||
* @brief STM32 TRNG subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup TRNG
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief TRNGD0 driver identifier.
|
||||
*/
|
||||
#if (SAMA_TRNG_USE_TRNG0 == TRUE) || defined(__DOXYGEN__)
|
||||
TRNGDriver TRNGD0;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static const TRNGConfig default_cfg = {0};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level TRNG driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void trng_lld_init(void) {
|
||||
|
||||
#if SAMA_TRNG_USE_TRNG0 == TRUE
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TRNG, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/* Driver initialization.*/
|
||||
trngObjectInit(&TRNGD0);
|
||||
TRNGD0.trng = TRNG;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the TRNG peripheral.
|
||||
*
|
||||
* @param[in] trngp pointer to the @p TRNGDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void trng_lld_start(TRNGDriver *trngp) {
|
||||
|
||||
/* There is no real configuration but setting up a valid pointer anyway.*/
|
||||
if (trngp->config == NULL) {
|
||||
trngp->config = &default_cfg;
|
||||
}
|
||||
|
||||
if (trngp->state == TRNG_STOP) {
|
||||
/* Enables the peripheral.*/
|
||||
#if SAMA_TRNG_USE_TRNG0 == TRUE
|
||||
if (&TRNGD0 == trngp) {
|
||||
pmcEnableTRNG0();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* Configures the peripheral.*/
|
||||
trngp->trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the TRNG peripheral.
|
||||
*
|
||||
* @param[in] trngp pointer to the @p TRNGDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void trng_lld_stop(TRNGDriver *trngp) {
|
||||
|
||||
if (trngp->state == TRNG_READY) {
|
||||
/* Resets the peripheral.*/
|
||||
trngp->trng->TRNG_CR = TRNG_CR_KEY_PASSWD;
|
||||
|
||||
/* Disables the peripheral.*/
|
||||
#if SAMA_TRNG_USE_TRNG0 == TRUE
|
||||
if (&TRNGD0 == trngp) {
|
||||
pmcDisableTRNG0();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief True random numbers generator.
|
||||
* @note The function is blocking and likely performs polled waiting
|
||||
* inside the low level implementation.
|
||||
*
|
||||
* @param[in] trngp pointer to the @p TRNGDriver object
|
||||
* @param[in] size size of output buffer
|
||||
* @param[out] out output buffer
|
||||
* @return The operation status.
|
||||
* @retval false if a random number has been generated.
|
||||
* @retval true if an HW error occurred.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out) {
|
||||
|
||||
while (true) {
|
||||
uint32_t r, tmo;
|
||||
size_t i;
|
||||
|
||||
/* Waiting for a random number in data register.*/
|
||||
tmo = SAMA_DATA_FETCH_ATTEMPTS;
|
||||
while ((tmo > 0) && ((trngp->trng->TRNG_ISR & TRNG_ISR_DATRDY) == 0)) {
|
||||
tmo--;
|
||||
if (tmo == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Getting the generated random number.*/
|
||||
r = trngp->trng->TRNG_ODATA;
|
||||
|
||||
/* Writing in the output buffer.*/
|
||||
for (i = 0; i < sizeof (uint32_t) / sizeof (uint8_t); i++) {
|
||||
*out++ = (uint8_t)r;
|
||||
r = r >> 8;
|
||||
size--;
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_TRNG == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_trng_lld.h
|
||||
* @brief SAMA TRNG subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup TRNG
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_TRNG_LLD_H
|
||||
#define HAL_TRNG_LLD_H
|
||||
|
||||
#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name SAMA configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief TRNGD0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TRNGD0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_TRNG_USE_TRNG0) || defined(__DOXYGEN__)
|
||||
#define SAMA_TRNG_USE_TRNG0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TRNGD0 data available timeout counter.
|
||||
* @details Number of status register fetches before failing.
|
||||
*/
|
||||
#if !defined(SAMA_DATA_FETCH_ATTEMPTS) || defined(__DOXYGEN__)
|
||||
#define SAMA_DATA_FETCH_ATTEMPTS 1000
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !SAMA_TRNG_USE_TRNG0
|
||||
#error "TRNG driver activated but no RNG peripheral assigned"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the TRNG configuration structure.
|
||||
*/
|
||||
#define trng_lld_config_fields \
|
||||
/* Dummy configuration, it is not needed.*/ \
|
||||
uint32_t dummy
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the TRNG driver structure.
|
||||
*/
|
||||
#define trng_lld_driver_fields \
|
||||
/* Pointer to the RNG registers block.*/ \
|
||||
Trng *trng;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (SAMA_TRNG_USE_TRNG0 == TRUE) && !defined(__DOXYGEN__)
|
||||
extern TRNGDriver TRNGD0;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void trng_lld_init(void);
|
||||
void trng_lld_start(TRNGDriver *trngp);
|
||||
void trng_lld_stop(TRNGDriver *trngp);
|
||||
bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_TRNG == TRUE */
|
||||
|
||||
#endif /* HAL_TRNG_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RTCv1
|
|
@ -1,658 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
|
||||
aka barthess.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file RTCv1/hal_rtc_lld.c
|
||||
* @brief SAMA RTC low level driver.
|
||||
*
|
||||
* @addtogroup RTC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_RTC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
#define RTC_TIMR_PM_OFFSET 22
|
||||
#define RTC_TIMR_HT_OFFSET 20
|
||||
#define RTC_TIMR_HU_OFFSET 16
|
||||
#define RTC_TIMR_MNT_OFFSET 12
|
||||
#define RTC_TIMR_MNU_OFFSET 8
|
||||
#define RTC_TIMR_ST_OFFSET 4
|
||||
#define RTC_TIMR_SU_OFFSET 0
|
||||
|
||||
#define RTC_CALR_DT_OFFSET 28
|
||||
#define RTC_CALR_DU_OFFSET 24
|
||||
#define RTC_CALR_WDU_OFFSET 21
|
||||
#define RTC_CALR_MT_OFFSET 20
|
||||
#define RTC_CALR_MU_OFFSET 16
|
||||
#define RTC_CALR_YT_OFFSET 12
|
||||
#define RTC_CALR_YU_OFFSET 8
|
||||
#define RTC_CALR_CT_OFFSET 4
|
||||
#define RTC_CALR_CU_OFFSET 0
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief RTC driver identifier.
|
||||
*/
|
||||
RTCDriver RTCD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief RTC interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_RTC_HANDLER) {
|
||||
uint16_t sr, imr;
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
sr = RTCD0.rtc->RTC_SR;
|
||||
imr = RTCD0.rtc->RTC_IMR;
|
||||
|
||||
if ((sr & RTC_SR_SEC) && (imr & RTC_IMR_SEC)) {
|
||||
RTCD0.rtc->RTC_SCCR = RTC_SCCR_SECCLR;
|
||||
RTCD0.callback(&RTCD0, RTC_EVENT_SECOND);
|
||||
}
|
||||
if ((sr & RTC_SR_ALARM) && (imr & RTC_IMR_ALR)) {
|
||||
RTCD0.rtc->RTC_SCCR = RTC_SCCR_ALRCLR;
|
||||
RTCD0.callback(&RTCD0, RTC_EVENT_ALARM);
|
||||
}
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Beginning of configuration procedure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void rtc_enter_init(void) {
|
||||
|
||||
/* Stop RTC_TIMR and RTC_CALR */
|
||||
RTCD0.rtc->RTC_CR |= RTC_CR_UPDCAL;
|
||||
RTCD0.rtc->RTC_CR |= RTC_CR_UPDTIM;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalizing of configuration procedure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void rtc_exit_init(void) {
|
||||
|
||||
RTCD0.rtc->RTC_CR &= ~RTC_CR_UPDTIM;
|
||||
RTCD0.rtc->RTC_CR &= ~RTC_CR_UPDCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts time from RTC_TIMR register encoding to timespec.
|
||||
*
|
||||
* @param[in] timr TIMR register value
|
||||
* @param[out] timespec pointer to a @p RTCDateTime structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void rtc_decode_time(uint32_t timr, RTCDateTime *timespec) {
|
||||
uint32_t n;
|
||||
|
||||
n = ((timr >> RTC_TIMR_HT_OFFSET) & 3) * 36000000;
|
||||
n += ((timr >> RTC_TIMR_HU_OFFSET) & 15) * 3600000;
|
||||
n += ((timr >> RTC_TIMR_MNT_OFFSET) & 7) * 600000;
|
||||
n += ((timr >> RTC_TIMR_MNU_OFFSET) & 15) * 60000;
|
||||
n += ((timr >> RTC_TIMR_ST_OFFSET) & 7) * 10000;
|
||||
n += ((timr >> RTC_TIMR_SU_OFFSET) & 15) * 1000;
|
||||
timespec->millisecond = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts date from RTC_CALR register encoding to timespec.
|
||||
*
|
||||
* @param[in] calr RTC_CALR register value
|
||||
* @param[out] timespec pointer to a @p RTCDateTime structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void rtc_decode_date(uint32_t calr, RTCDateTime *timespec) {
|
||||
|
||||
uint32_t centuryYear = (((calr >> RTC_CALR_CT_OFFSET) & 7) * 1000) +
|
||||
(((calr >> RTC_CALR_CU_OFFSET) & 15) * 100) +
|
||||
(((calr >> RTC_CALR_YT_OFFSET) & 15) * 10) +
|
||||
((calr >> RTC_CALR_YU_OFFSET) & 15);
|
||||
timespec->year = (centuryYear - 1980);
|
||||
timespec->month = (((calr >> RTC_CALR_MT_OFFSET) & 1) * 10) +
|
||||
((calr >> RTC_CALR_MU_OFFSET) & 15);
|
||||
timespec->day = (((calr >> RTC_CALR_DT_OFFSET) & 3) * 10) +
|
||||
((calr >> RTC_CALR_DU_OFFSET) & 15);
|
||||
timespec->dayofweek = (calr >> RTC_CALR_WDU_OFFSET) & 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts time from timespec to RTC_TIMR register encoding.
|
||||
*
|
||||
* @param[in] timespec pointer to a @p RTCDateTime structure
|
||||
* @return the TIMR register encoding.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static uint32_t rtc_encode_time(const RTCDateTime *timespec) {
|
||||
uint32_t n, timr = 0;
|
||||
|
||||
/* Subseconds cannot be set.*/
|
||||
n = timespec->millisecond / 1000;
|
||||
|
||||
/* Seconds conversion.*/
|
||||
timr = timr | ((n % 10) << RTC_TIMR_SU_OFFSET);
|
||||
n /= 10;
|
||||
timr = timr | ((n % 6) << RTC_TIMR_ST_OFFSET);
|
||||
n /= 6;
|
||||
|
||||
/* Minutes conversion.*/
|
||||
timr = timr | ((n % 10) << RTC_TIMR_MNU_OFFSET);
|
||||
n /= 10;
|
||||
timr = timr | ((n % 6) << RTC_TIMR_MNT_OFFSET);
|
||||
n /= 6;
|
||||
|
||||
/* Hours conversion.*/
|
||||
timr = timr | ((n % 10) << RTC_TIMR_HU_OFFSET);
|
||||
n /= 10;
|
||||
timr = timr | (n << RTC_TIMR_HT_OFFSET);
|
||||
|
||||
return timr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a date from timespec to RTC_CALR register encoding.
|
||||
*
|
||||
* @param[in] timespec pointer to a @p RTCDateTime structure
|
||||
* @return the CALR register encoding.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static uint32_t rtc_encode_date(const RTCDateTime *timespec) {
|
||||
uint32_t n, calr = 0;
|
||||
|
||||
/* Year conversion. */
|
||||
n = timespec->year + 1980;
|
||||
calr = calr | ((n % 10) << RTC_CALR_YU_OFFSET);
|
||||
n /= 10;
|
||||
calr = calr | ((n % 10) << RTC_CALR_YT_OFFSET);
|
||||
n /= 10;
|
||||
calr = calr | ((n % 10) << RTC_CALR_CU_OFFSET);
|
||||
n /= 10;
|
||||
calr = calr | ((n % 10) << RTC_CALR_CT_OFFSET);
|
||||
|
||||
/* Months conversion.*/
|
||||
n = timespec->month;
|
||||
calr = calr | ((n % 10) << RTC_CALR_MU_OFFSET);
|
||||
n /= 10;
|
||||
calr = calr | ((n % 10) << RTC_CALR_MT_OFFSET);
|
||||
|
||||
/* Days conversion.*/
|
||||
n = timespec->day;
|
||||
calr = calr | ((n % 10) << RTC_CALR_DU_OFFSET);
|
||||
n /= 10;
|
||||
calr = calr | ((n % 10) << RTC_CALR_DT_OFFSET);
|
||||
|
||||
/* Days of week conversion.*/
|
||||
calr = calr | (timespec->dayofweek << RTC_CALR_WDU_OFFSET);
|
||||
|
||||
return calr;
|
||||
}
|
||||
|
||||
#if RTC_HAS_STORAGE
|
||||
/* TODO: Map on the backup SRAM on devices that have it.*/
|
||||
static size_t _write(void *instance, const uint8_t *bp, size_t n) {
|
||||
|
||||
(void)instance;
|
||||
(void)bp;
|
||||
(void)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t _read(void *instance, uint8_t *bp, size_t n) {
|
||||
|
||||
(void)instance;
|
||||
(void)bp;
|
||||
(void)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t _put(void *instance, uint8_t b) {
|
||||
|
||||
(void)instance;
|
||||
(void)b;
|
||||
|
||||
return FILE_OK;
|
||||
}
|
||||
|
||||
static msg_t _get(void *instance) {
|
||||
|
||||
(void)instance;
|
||||
|
||||
return FILE_OK;
|
||||
}
|
||||
|
||||
static msg_t _close(void *instance) {
|
||||
|
||||
/* Close is not supported.*/
|
||||
(void)instance;
|
||||
|
||||
return FILE_OK;
|
||||
}
|
||||
|
||||
static msg_t _geterror(void *instance) {
|
||||
|
||||
(void)instance;
|
||||
|
||||
return (msg_t)0;
|
||||
}
|
||||
|
||||
static msg_t _getsize(void *instance) {
|
||||
|
||||
(void)instance;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t _getposition(void *instance) {
|
||||
|
||||
(void)instance;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static msg_t _lseek(void *instance, fileoffset_t offset) {
|
||||
|
||||
(void)instance;
|
||||
(void)offset;
|
||||
|
||||
return FILE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief VMT for the RTC storage file interface.
|
||||
*/
|
||||
struct RTCDriverVMT _rtc_lld_vmt = {
|
||||
_write, _read, _put, _get,
|
||||
_close, _geterror, _getsize, _getposition, _lseek
|
||||
};
|
||||
#endif /* RTC_HAS_STORAGE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable access to registers.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_init(void) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SYSC, SECURE_PER);
|
||||
#endif
|
||||
|
||||
/* RTC object initialization.*/
|
||||
rtcObjectInit(&RTCD0);
|
||||
|
||||
/* RTC pointer initialization.*/
|
||||
RTCD0.rtc = RTC;
|
||||
|
||||
/* Disable write protection */
|
||||
// syscDisableWP();
|
||||
|
||||
RTCD0.rtc->RTC_IDR = RTC_IDR_ALRDIS | RTC_IDR_SECDIS;
|
||||
|
||||
/* Clear all status flag.*/
|
||||
RTCD0.rtc->RTC_SCCR = 0x3F;
|
||||
|
||||
/* Disable match alarms */
|
||||
RTCD0.rtc->RTC_TIMALR &= ~(RTC_TIMALR_SECEN | RTC_TIMALR_MINEN | RTC_TIMALR_HOUREN);
|
||||
RTCD0.rtc->RTC_CALALR &= ~(RTC_CALALR_MTHEN | RTC_CALALR_DATEEN);
|
||||
|
||||
/* Callback initially disabled.*/
|
||||
RTCD0.callback = NULL;
|
||||
|
||||
/* Enable write protection */
|
||||
// syscEnableWP();
|
||||
|
||||
/* IRQ vector permanently assigned to this driver.*/
|
||||
aicSetSourcePriority(ID_SYSC, SAMA_RTC_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_SYSC, SAMA_RTC_HANDLER);
|
||||
aicEnableInt(ID_SYSC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set current time.
|
||||
* @note Fractional part will be silently ignored.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] timespec pointer to a @p RTCDateTime structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) {
|
||||
uint32_t calr, timr, ver;
|
||||
syssts_t sts;
|
||||
|
||||
timr = rtc_encode_time(timespec);
|
||||
calr = rtc_encode_date(timespec);
|
||||
ver = rtcp->rtc->RTC_VER;
|
||||
|
||||
/* Disable write protection */
|
||||
// syscDisableWP();
|
||||
|
||||
/* Synchronization on a second periodic event polling the RTC_SR.SEC status bit */
|
||||
wait: while ((rtcp->rtc->RTC_SR & RTC_SR_SEC) == 0);
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
if (!(rtcp->rtc->RTC_SR & RTC_SR_SEC)) {
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
goto wait;
|
||||
}
|
||||
|
||||
/* Writing the registers.*/
|
||||
rtc_enter_init();
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
|
||||
while ((RTCD0.rtc->RTC_SR & RTC_SR_ACKUPD) == 0);
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
if (!(rtcp->rtc->RTC_SR & RTC_SR_SEC)) {
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
goto wait;
|
||||
}
|
||||
|
||||
/* Clear ACKUPD status flag */
|
||||
rtcp->rtc->RTC_SCCR = RTC_SCCR_ACKCLR;
|
||||
|
||||
/* Date and Time updating */
|
||||
rtcp->rtc->RTC_TIMR = timr;
|
||||
rtcp->rtc->RTC_CALR = calr;
|
||||
|
||||
rtc_exit_init();
|
||||
|
||||
/* Enable write protection */
|
||||
// syscEnableWP();
|
||||
|
||||
/* Check time and data fields */
|
||||
osalDbgAssert(((ver & RTC_VER_NVCAL) == 0) || ((ver & RTC_VER_NVTIM) == 0),
|
||||
"invalid date-time");
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current time.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[out] timespec pointer to a @p RTCDateTime structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) {
|
||||
uint32_t calr, timr;
|
||||
uint32_t subs = 0;
|
||||
syssts_t sts;
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
do {
|
||||
timr = rtcp->rtc->RTC_TIMR;
|
||||
} while (timr != rtcp->rtc->RTC_TIMR);
|
||||
|
||||
do {
|
||||
calr = rtcp->rtc->RTC_CALR;
|
||||
} while (calr != rtcp->rtc->RTC_CALR);
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
|
||||
rtc_decode_time(timr, timespec);
|
||||
timespec->millisecond += subs;
|
||||
|
||||
/* Decoding date, this concludes the atomic read sequence.*/
|
||||
rtc_decode_date(calr, timespec);
|
||||
|
||||
/* Retrieving the DST bit.*/
|
||||
timespec->dstflag = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get tamper time.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] reg number of register to return
|
||||
* @param[out] timespec pointer to a @p RTCDateTime structure
|
||||
*
|
||||
* @note RTC_TSSR0 and RTC_TSDR cannot be overwritten, so once it has been written
|
||||
* all data are stored until the registers are reset: these register are
|
||||
* storing the first tamper occurrence after a read.
|
||||
* RTC_TSSR0 and RTC_TSDR are overwritten each time a tamper event is detected.
|
||||
*
|
||||
*/
|
||||
void rtcGetTamperTime(RTCDriver *rtcp, uint8_t reg, RTCDateTime *timespec) {
|
||||
uint32_t calr, timr;
|
||||
uint32_t subs = 0;
|
||||
|
||||
timr = rtcp->rtc->RTC_TS[reg].RTC_TSTR;
|
||||
calr = rtcp->rtc->RTC_TS[reg].RTC_TSDR;
|
||||
|
||||
rtc_decode_time(timr, timespec);
|
||||
timespec->millisecond += subs;
|
||||
|
||||
/* Decoding date, this concludes the atomic read sequence.*/
|
||||
rtc_decode_date(calr, timespec);
|
||||
|
||||
/* Retrieving the DST bit.*/
|
||||
timespec->dstflag = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns source of tamper register.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] reg number of register source to return
|
||||
*
|
||||
* return content of RTC_SSRx register
|
||||
*
|
||||
* @note RTC_TSSR0 cannot be overwritten, so once it has been written
|
||||
* all data are stored until the registers are reset: that register is
|
||||
* storing the first tamper occurrence after a read.
|
||||
* RTC_TSSR1 is overwritten each time a tamper event is detected.
|
||||
*
|
||||
*/
|
||||
uint32_t rtcGetTamperSource(RTCDriver *rtcp, uint8_t reg) {
|
||||
return ((rtcp)->rtc->RTC_TS[reg].RTC_TSSR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns numbers of total tamper events.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
*
|
||||
* return numbers of total tamper events.
|
||||
*/
|
||||
uint32_t rtcGetTamperEventCounter(RTCDriver *rtcp) {
|
||||
return ((rtcp)->rtc->RTC_TS[0].RTC_TSTR & RTC_TSTR_TEVCNT_Msk) >> RTC_TSTR_TEVCNT_Pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns backup or normal mode of tamper event.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] reg number of register source to return
|
||||
*
|
||||
* @return 0x1 if system is in backup mode when tamper events occurs
|
||||
* 0x0 if system is not in backup mode when tamper events occurs
|
||||
*
|
||||
* @note RTC_TSTR0 cannot be overwritten, so once it has been written
|
||||
* all data are stored until the registers are reset: that register is
|
||||
* storing the first tamper occurrence after a read.
|
||||
* RTC_TSTR1 is overwritten each time a tamper event is detected.
|
||||
*
|
||||
*/
|
||||
uint8_t rtcGetTamperMode(RTCDriver *rtcp, uint8_t reg) {
|
||||
return (rtcp)->rtc->RTC_TS[reg].RTC_TSTR & RTC_TSTR_BACKUP ? 0x1u : 0x0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set alarm time.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure.
|
||||
* @param[in] alarm alarm identifier.
|
||||
* @param[in] alarmspec pointer to a @p RTCAlarm structure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_set_alarm(RTCDriver *rtcp,
|
||||
rtcalarm_t alarm,
|
||||
const RTCAlarm *alarmspec) {
|
||||
|
||||
/* SAMA has only one alarm, this field is ignored */
|
||||
(void)alarm;
|
||||
syssts_t sts;
|
||||
|
||||
/* Disable write protection */
|
||||
// syscDisableWP();
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
if (alarmspec != NULL) {
|
||||
if (alarmspec->timralrm != 0){
|
||||
rtcp->rtc->RTC_TIMALR = alarmspec->timralrm;
|
||||
/* Check time alarm fields */
|
||||
osalDbgAssert(((rtcp->rtc->RTC_VER & RTC_VER_NVTIMALR) == 0),
|
||||
"invalid time-alarm");
|
||||
}
|
||||
if (alarmspec->calralrm != 0){
|
||||
rtcp->rtc->RTC_CALALR = alarmspec->calralrm;
|
||||
/* Check calendar alarm fields */
|
||||
osalDbgAssert(((rtcp->rtc->RTC_VER & RTC_VER_NVCALALR) == 0),
|
||||
"invalid date-alarm");
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtcp->rtc->RTC_TIMALR = 0;
|
||||
rtcp->rtc->RTC_CALALR = 0;
|
||||
}
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
|
||||
/* Enable write protection */
|
||||
// syscEnableWP();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get alarm time.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] alarm alarm identifier
|
||||
* @param[out] alarmspec pointer to a @p RTCAlarm structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_get_alarm(RTCDriver *rtcp,
|
||||
rtcalarm_t alarm,
|
||||
RTCAlarm *alarmspec) {
|
||||
|
||||
(void)alarm;
|
||||
alarmspec->timralrm = rtcp->rtc->RTC_TIMALR;
|
||||
alarmspec->calralrm = rtcp->rtc->RTC_CALALR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables or disables RTC callbacks.
|
||||
* @details This function enables or disables callbacks, use a @p NULL pointer
|
||||
* in order to disable a callback.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] callback callback function pointer or @p NULL
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
|
||||
syssts_t sts;
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
if (callback != NULL) {
|
||||
|
||||
/* IRQ sources enabled only after setting up the callback.*/
|
||||
rtcp->callback = callback;
|
||||
|
||||
rtcp->rtc->RTC_SCCR = RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR | RTC_SCCR_TIMCLR |
|
||||
RTC_SCCR_CALCLR | RTC_SCCR_TDERRCLR;
|
||||
rtcp->rtc->RTC_IER = RTC_IER_ALREN | RTC_IER_SECEN;
|
||||
}
|
||||
else {
|
||||
rtcp->rtc->RTC_IDR = RTC_IDR_ALRDIS | RTC_IDR_SECDIS;
|
||||
|
||||
/* Callback set to NULL only after disabling the IRQ sources.*/
|
||||
rtcp->callback = NULL;
|
||||
}
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_RTC */
|
||||
|
||||
/** @} */
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
|
||||
aka barthess.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file RTCv1/hal_rtc_lld.h
|
||||
* @brief SAMA RTC low level driver header.
|
||||
*
|
||||
* @addtogroup RTC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_RTC_LLD_H
|
||||
#define HAL_RTC_LLD_H
|
||||
|
||||
#if HAL_USE_RTC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
#define SYSC_WPMR (0xF80480E4u)
|
||||
#define SYSC_WPMR_WPKEY_PASSWD (0x535943u << 8)
|
||||
#define SYSC_WPMR_WPEN (0x1u << 0)
|
||||
|
||||
/**
|
||||
* @name Implementation capabilities
|
||||
*/
|
||||
/**
|
||||
* @brief Number of available alarms.
|
||||
*/
|
||||
#define RTC_ALARMS 1
|
||||
|
||||
/**
|
||||
* @brief Presence of a local persistent storage.
|
||||
*/
|
||||
#define RTC_HAS_STORAGE FALSE
|
||||
|
||||
/**
|
||||
* @brief Callback supported.
|
||||
*/
|
||||
#define RTC_SUPPORTS_CALLBACKS TRUE
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/*
|
||||
* RTC driver system settings.
|
||||
*/
|
||||
#define SAMA_RTC_IRQ_PRIORITY 7
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of an RTC event.
|
||||
*/
|
||||
typedef enum {
|
||||
RTC_EVENT_SECOND = 0, /** Triggered every second. */
|
||||
RTC_EVENT_ALARM = 1 /** Triggered on alarm. */
|
||||
} rtcevent_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a generic RTC callback.
|
||||
*/
|
||||
typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an RTC alarm time stamp.
|
||||
*/
|
||||
typedef struct hal_rtc_alarm {
|
||||
/**
|
||||
* @brief Type of an alarm as encoded in RTC registers.
|
||||
*/
|
||||
uint32_t timralrm;
|
||||
uint32_t calralrm;
|
||||
} RTCAlarm;
|
||||
|
||||
/**
|
||||
* @brief Implementation-specific @p RTCDriver fields.
|
||||
*/
|
||||
#define rtc_lld_driver_fields \
|
||||
/* Pointer to the RTC registers block.*/ \
|
||||
Rtc *rtc; \
|
||||
/* Callback pointer.*/ \
|
||||
rtccb_t callback
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Enable write protection on SYSC registers block.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define syscEnableWP() { \
|
||||
*(uint32_t *)(SYSC_WPMR) = SYSC_WPMR_WPKEY_PASSWD | SYSC_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on SYSC registers block.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define syscDisableWP() { \
|
||||
*(uint32_t *)(SYSC_WPMR) = SYSC_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure RTC_MR register.
|
||||
*
|
||||
* @param[in] rtcp pointer to RTC driver structure
|
||||
* @param[in] value value to be written in the MR register
|
||||
*
|
||||
*/
|
||||
#define rtcConfigureMode(rtcp, value) { \
|
||||
(rtcp)->rtc->RTC_MR = value; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void rtc_lld_init(void);
|
||||
void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec);
|
||||
void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec);
|
||||
void rtc_lld_set_alarm(RTCDriver *rtcp,
|
||||
rtcalarm_t alarm,
|
||||
const RTCAlarm *alarmspec);
|
||||
void rtc_lld_get_alarm(RTCDriver *rtcp,
|
||||
rtcalarm_t alarm,
|
||||
RTCAlarm *alarmspec);
|
||||
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
|
||||
/* Driver specific */
|
||||
void rtcGetTamperTime(RTCDriver *rtcp, uint8_t reg, RTCDateTime *timespec);
|
||||
uint32_t rtcGetTamperSource(RTCDriver *rtcp, uint8_t reg);
|
||||
uint32_t rtcGetTamperEventCounter(RTCDriver *rtcp);
|
||||
uint8_t rtcGetTamperMode(RTCDriver *rtcp, uint8_t reg);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_RTC */
|
||||
|
||||
#endif /* HAL_RTC_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,512 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "hal.h"
|
||||
|
||||
#if (SAMA_USE_SDMMC == TRUE)
|
||||
|
||||
#include "sama_sdmmc_lld.h"
|
||||
#include "ch_sdmmc_device.h"
|
||||
#include "ch_sdmmc_cmds.h"
|
||||
#include "ch_sdmmc_sdio.h"
|
||||
#include "ch_sdmmc_sd.h"
|
||||
#include "ch_sdmmc_mmc.h"
|
||||
|
||||
/** SD/MMC transfer rate unit codes (10K) list */
|
||||
const uint16_t sdmmcTransUnits[8] = {
|
||||
10, 100, 1000, 10000,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
/** SD transfer multiplier factor codes (1/10) list */
|
||||
const uint8_t sdTransMultipliers[16] = {
|
||||
0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
|
||||
};
|
||||
|
||||
|
||||
|
||||
uint32_t SdmmcGetMaxFreq(SdmmcDriver *drv)
|
||||
{
|
||||
uint32_t rate = 0;
|
||||
sSdCard * pSd = &drv->card;
|
||||
|
||||
#ifndef SDMMC_TRIM_MMC
|
||||
if ((pSd->bCardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmMMC) {
|
||||
if (pSd->bSpeedMode == SDMMC_TIM_MMC_HS200)
|
||||
rate = 200000ul;
|
||||
else if (pSd->bSpeedMode == SDMMC_TIM_MMC_HS_DDR
|
||||
|| (pSd->bSpeedMode == SDMMC_TIM_MMC_HS_SDR
|
||||
&& MMC_EXT_CARD_TYPE(pSd->EXT) & 0x2))
|
||||
rate = 52000ul;
|
||||
else if (pSd->bSpeedMode == SDMMC_TIM_MMC_HS_SDR)
|
||||
rate = 26000ul;
|
||||
else
|
||||
rate = SdmmcDecodeTransSpeed(SD_CSD_TRAN_SPEED(pSd->CSD),
|
||||
sdmmcTransUnits, mmcTransMultipliers);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((pSd->bCardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmSD) {
|
||||
rate = SdmmcDecodeTransSpeed(SD_CSD_TRAN_SPEED(pSd->CSD),
|
||||
sdmmcTransUnits, sdTransMultipliers);
|
||||
if (pSd->bSpeedMode == SDMMC_TIM_SD_SDR104 && rate == 200000ul)
|
||||
rate = 208000ul;
|
||||
else if (pSd->bSpeedMode == SDMMC_TIM_SD_DDR50)
|
||||
rate /= 2ul;
|
||||
}
|
||||
|
||||
TRACE_DEBUG_1("SdmmcGetMaxFreq rate %d\r\n",rate);
|
||||
return rate * 1000ul;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update SD/MMC information.
|
||||
* Update CSD for card speed switch.
|
||||
* Update ExtDATA for any card function switch.
|
||||
* \param pSd Pointer to a SD card driver instance.
|
||||
* \return error code when update CSD error.
|
||||
*/
|
||||
void SdMmcUpdateInformation(SdmmcDriver *drv, bool csd, bool extData)
|
||||
{
|
||||
uint8_t error;
|
||||
|
||||
/* Update CSD for new TRAN_SPEED value */
|
||||
if (csd) {
|
||||
|
||||
SdMmcSelect(drv, 0, 1);
|
||||
|
||||
/* Wait for 14 usec (or more) */
|
||||
t_usleep(drv,20);
|
||||
|
||||
error = Cmd9(drv);
|
||||
|
||||
if (error)
|
||||
return;
|
||||
|
||||
SdMmcSelect(drv, drv->card.wAddress, 1);
|
||||
}
|
||||
if (extData) {
|
||||
if ((drv->card.bCardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmSD)
|
||||
SdGetExtInformation(drv);
|
||||
#ifndef SDMMC_TRIM_MMC
|
||||
else if ((drv->card.bCardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmMMC)
|
||||
MmcGetExtInformation(drv);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry)
|
||||
{
|
||||
uint64_t mem_size;
|
||||
uint32_t freq;
|
||||
uint32_t drv_err, status;
|
||||
uint8_t error;
|
||||
bool flag;
|
||||
sSdCard *pSd = &drv->card;
|
||||
|
||||
*retry = false;
|
||||
|
||||
drv->card.bSpeedMode = drv->card.bCardSigLevel == 0 ? SDMMC_TIM_SD_SDR12 : SDMMC_TIM_SD_DS;
|
||||
drv->timeout_elapsed = -1;
|
||||
HwSetHsMode(drv, drv->card.bSpeedMode);
|
||||
|
||||
/* Consider switching to low signaling level, as a prerequisite to
|
||||
* switching to any UHS-I timing mode */
|
||||
if (drv->card.bCardSigLevel == 1) {
|
||||
|
||||
error = Cmd11(drv, &status);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if ((status & STATUS_STATE) != STATUS_READY) {
|
||||
TRACE_1("st %lx\n\r", status);
|
||||
}
|
||||
|
||||
drv->card.bCardSigLevel = 0;
|
||||
error = HwPowerDevice(drv, SDMMC_PWR_STD_VDD_LOW_IO);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = HwSetHsMode(drv, SDMMC_TIM_SD_SDR12);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
drv->card.bSpeedMode = SDMMC_TIM_SD_SDR12;
|
||||
}
|
||||
|
||||
/* The host then issues the command ALL_SEND_CID (CMD2) to the card to get
|
||||
* its unique card identification (CID) number.
|
||||
* Card that is unidentified (i.e. which is in Ready State) sends its CID
|
||||
* number as the response (on the CMD line). */
|
||||
error = Cmd2(drv);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Thereafter, the host issues CMD3 (SEND_RELATIVE_ADDR) asks the
|
||||
* card to publish a new relative card address (RCA), which is shorter than
|
||||
* CID and which is used to address the card in the future data transfer
|
||||
* mode. Once the RCA is received the card state changes to the Stand-by
|
||||
* State. At this point, if the host wants to assign another RCA number, it
|
||||
* can ask the card to publish a new number by sending another CMD3 command
|
||||
* to the card. The last published RCA is the actual RCA number of the
|
||||
* card. */
|
||||
error = Cmd3(drv);
|
||||
if (error)
|
||||
return error;
|
||||
else {
|
||||
TRACE_DEBUG_1("RCA=%u\n\r",drv->card.wAddress );
|
||||
}
|
||||
|
||||
/* SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
|
||||
* e.g. block length, card storage capacity, etc... */
|
||||
error = Cmd9(drv);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Now select the card, to TRAN state */
|
||||
error = SdMmcSelect(drv, drv->card.wAddress , 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Get extended information of the card */
|
||||
SdMmcUpdateInformation(drv, true, true);
|
||||
|
||||
/* Enable more bus width Mode */
|
||||
error = SdDecideBuswidth(drv);
|
||||
if (error) {
|
||||
//trace_error("Bus width %s\n\r", SD_StringifyRetCode(error));
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
|
||||
/* Consider HS and UHS-I timing modes */
|
||||
error = SdEnableHighSpeed(drv);
|
||||
if (error) {
|
||||
*retry = error == (SDMMC_STATE && (&drv->card.bCardSigLevel != 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Update card information since status changed */
|
||||
flag = drv->card.bSpeedMode != SDMMC_TIM_SD_DS
|
||||
&& drv->card.bSpeedMode != SDMMC_TIM_SD_SDR12;
|
||||
if (flag || drv->card.bBusMode > 1)
|
||||
SdMmcUpdateInformation(drv, flag, true);
|
||||
|
||||
/* Find out if the device supports the SET_BLOCK_COUNT command.
|
||||
* SD devices advertise in SCR.CMD_SUPPORT whether or not they handle
|
||||
* the SET_BLOCK_COUNT command. */
|
||||
drv->card.bSetBlkCnt = SD_SCR_CMD23_SUPPORT(pSd->SCR);
|
||||
/* Now, if the device does not support the SET_BLOCK_COUNT command, then
|
||||
* the legacy STOP_TRANSMISSION command shall be issued, though not at
|
||||
* the same timing. */
|
||||
if (!drv->card.bSetBlkCnt) {
|
||||
/* In case the driver does not automatically issue the
|
||||
* STOP_TRANSMISSION command, we'll have to do it ourselves. */
|
||||
|
||||
drv->control_param = 0;
|
||||
drv_err = sdmmc_device_control(drv, SDMMC_IOCTL_GET_XFERCOMPL);
|
||||
|
||||
if (drv_err != SDMMC_OK || !drv->control_param)
|
||||
drv->card.bStopMultXfer = 1;
|
||||
}
|
||||
/* Ask the driver to implicitly send the SET_BLOCK_COUNT command,
|
||||
* immediately before every READ_MULTIPLE_BLOCK and WRITE_MULTIPLE_BLOCK
|
||||
* command. Or, if the current device does not support SET_BLOCK_COUNT,
|
||||
* instruct the driver to stop using this command. */
|
||||
drv->control_param = pSd->bSetBlkCnt;
|
||||
|
||||
drv_err = sdmmc_device_control(drv,SDMMC_IOCTL_SET_LENPREFIX);
|
||||
|
||||
/* In case the driver does not support this function, we'll take it in
|
||||
* charge. */
|
||||
if (drv->card.bSetBlkCnt && drv_err == SDMMC_OK && drv->control_param)
|
||||
drv->card.bSetBlkCnt = 0;
|
||||
|
||||
/* In the case of a Standard Capacity SD Memory Card, this command sets the
|
||||
* block length (in bytes) for all following block commands
|
||||
* (read, write, lock).
|
||||
* Default block length is fixed to 512 Bytes.
|
||||
* Set length is valid for memory access commands only if partial block read
|
||||
* operation are allowed in CSD.
|
||||
* In the case of a High Capacity SD Memory Card, block length set by CMD16
|
||||
* command does not affect the memory read and write commands. Always 512
|
||||
* Bytes fixed block length is used. This command is effective for
|
||||
* LOCK_UNLOCK command.
|
||||
* In both cases, if block length is set larger than 512Bytes, the card sets
|
||||
* the BLOCK_LEN_ERROR bit. */
|
||||
if (drv->card.bCardType == CARD_SD) {
|
||||
error = Cmd16(drv, SDMMC_BLOCK_SIZE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
drv->card.wCurrBlockLen = SDMMC_BLOCK_SIZE;
|
||||
|
||||
if (SD_CSD_STRUCTURE(pSd->CSD) >= 1) {
|
||||
drv->card.wBlockSize = 512;
|
||||
mem_size = SD_CSD_BLOCKNR_HC(pSd->CSD);
|
||||
drv->card.dwNbBlocks = mem_size >> 32 ? 0xFFFFFFFF : (uint32_t)mem_size;
|
||||
if (drv->card.dwNbBlocks >= 0x800000)
|
||||
drv->card.dwTotalSize = 0xFFFFFFFF;
|
||||
else
|
||||
drv->card.dwTotalSize = drv->card.dwNbBlocks * 512UL;
|
||||
}
|
||||
else {
|
||||
drv->card.wBlockSize = 512;
|
||||
mem_size = SD_CSD_TOTAL_SIZE(pSd->CSD);
|
||||
drv->card.dwNbBlocks = (uint32_t)(mem_size >> 9);
|
||||
drv->card.dwTotalSize = mem_size >> 32 ? 0xFFFFFFFF
|
||||
: (uint32_t)mem_size;
|
||||
}
|
||||
|
||||
|
||||
/* Automatically select the max device clock frequency */
|
||||
/* Calculate transfer speed */
|
||||
freq = SdmmcGetMaxFreq(drv);
|
||||
|
||||
#ifndef SDMMC_TRIM_SDIO
|
||||
if (drv->card.bCardType & CARD_TYPE_bmSDIO) {
|
||||
freq = min_u32(freq, SdioGetMaxFreq(drv));
|
||||
TRACE_INFO_1("selecting sdio freq%d\r\n",freq);
|
||||
}
|
||||
#endif
|
||||
error = HwSetClock(drv, &freq);
|
||||
drv->card.dwCurrSpeed = freq;
|
||||
if (error != SDMMC_OK && error != SDMMC_CHANGED) {
|
||||
TRACE_ERROR_1("error clk %s\n\r", SD_StringifyRetCode(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Check device status and eat past exceptions, which would otherwise
|
||||
* prevent upcoming data transaction routines from reliably checking
|
||||
* fresh exceptions. */
|
||||
error = Cmd13(drv, &status);
|
||||
if (error)
|
||||
return error;
|
||||
status = status & ~STATUS_STATE & ~STATUS_READY_FOR_DATA & ~STATUS_APP_CMD;
|
||||
|
||||
//warning
|
||||
if (status) {
|
||||
TRACE_WARNING_1("warning st %lx\n\r", status);
|
||||
}
|
||||
|
||||
return SDMMC_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Run the SD/MMC/SDIO Mode initialization sequence.
|
||||
* This function runs the initialization procedure and the identification
|
||||
* process. Then it leaves the card in ready state. The following procedure must
|
||||
* check the card type and continue to put the card into tran(for memory card)
|
||||
* or cmd(for io card) state for data exchange.
|
||||
* \param pSd Pointer to a SD card driver instance.
|
||||
* \return 0 if successful; otherwise returns an \ref sdmmc_rc "SD_ERROR code".
|
||||
*/
|
||||
uint8_t SdMmcIdentify(SdmmcDriver *drv)
|
||||
{
|
||||
uint8_t error;
|
||||
bool high_capacity;
|
||||
uint8_t dev_type = CARD_UNKNOWN;
|
||||
bool sd_v2 = false;
|
||||
|
||||
|
||||
#ifndef SDMMC_TRIM_SDIO
|
||||
/* Reset SDIO: CMD52, write 1 to RES bit in CCCR */
|
||||
{
|
||||
uint32_t status = SDIO_RES;
|
||||
|
||||
error = Cmd52(drv, 1, SDIO_CIA, 0, SDIO_IOA_REG, &status);
|
||||
|
||||
if ((error && error != SDMMC_NO_RESPONSE) || (!error && status & STATUS_SDIO_R5)) {
|
||||
TRACE_2("IOrst %s st %lx\n\r",
|
||||
SD_StringifyRetCode(error), status);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Reset MEM: CMD0 */
|
||||
error = Cmd0(drv, 0);
|
||||
|
||||
t_msleep(drv,200);
|
||||
|
||||
if (error) {
|
||||
TRACE_1("rst %s\n\r", SD_StringifyRetCode(error));
|
||||
}
|
||||
|
||||
|
||||
/* CMD8 is newly added in the Physical Layer Specification Version 2.00 to
|
||||
* support multiple voltage ranges and used to check whether the card
|
||||
* supports supplied voltage. The version 2.00 host shall issue CMD8 and
|
||||
* verify voltage before card initialization.
|
||||
* The host that does not support CMD8 shall supply high voltage range... */
|
||||
|
||||
|
||||
error = SdCmd8(drv, SD_IFC_VHS_27_36 >> SD_IFC_VHS_Pos);
|
||||
|
||||
if (!error)
|
||||
sd_v2 = true;
|
||||
else if (error != SDMMC_NO_RESPONSE)
|
||||
return SDMMC_ERR;
|
||||
else {
|
||||
/* No response to CMD8. Wait for 130 usec (or more). */
|
||||
t_usleep(drv,200);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SDMMC_TRIM_SDIO
|
||||
/* CMD5 is newly added for SDIO initialize & power on */
|
||||
{
|
||||
uint32_t status = 0;
|
||||
|
||||
error = Cmd5(drv, &status);
|
||||
|
||||
if (!error && (status & SDIO_OCR_NF) > 0) {
|
||||
|
||||
//int8_t elapsed;
|
||||
|
||||
/* Card has SDIO function. Wait until it raises the
|
||||
* IORDY flag, which may take up to 1s, i.e. 1000 system
|
||||
* ticks. */
|
||||
for (drv->timeout_elapsed = 0;
|
||||
!(status & SD_OCR_BUSYN) && !error && !drv->timeout_elapsed; ) {
|
||||
|
||||
|
||||
status &= SD_HOST_VOLTAGE_RANGE;
|
||||
error = Cmd5(drv, &status);
|
||||
}
|
||||
if (!(status & SD_OCR_BUSYN) && !error)
|
||||
error = SDMMC_BUSY;
|
||||
if (error) {
|
||||
TRACE_1("SDIO oc %s\n\r",SD_StringifyRetCode(error));
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
TRACE("SDIO\n\r");
|
||||
dev_type = status & SDIO_OCR_MP ? CARD_SDCOMBO : CARD_SDIO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev_type != CARD_SDIO) {
|
||||
/* The device should have memory (MMC or SD or COMBO).
|
||||
* Try to initialize SD memory. */
|
||||
bool low_sig_lvl = HwIsTimingSupported(drv, SDMMC_TIM_SD_SDR12);
|
||||
|
||||
high_capacity = sd_v2;
|
||||
error = Acmd41(drv, &low_sig_lvl, &high_capacity);
|
||||
if (!error) {
|
||||
TRACE_1("SD%s MEM\n\r", high_capacity ? "HC" : "");
|
||||
dev_type |= high_capacity ? CARD_SDHC : CARD_SD;
|
||||
if (drv->card.bCardSigLevel == 2 && low_sig_lvl)
|
||||
drv->card.bCardSigLevel = 1;
|
||||
}
|
||||
else if (dev_type == CARD_SDCOMBO)
|
||||
dev_type = CARD_SDIO;
|
||||
}
|
||||
|
||||
#ifndef SDMMC_TRIM_MMC
|
||||
if (dev_type == CARD_UNKNOWN) {
|
||||
/* Try MMC initialize */
|
||||
uint8_t count;
|
||||
|
||||
for (error = SDMMC_NO_RESPONSE, count = 0;
|
||||
error == SDMMC_NO_RESPONSE && count < 10;
|
||||
count++)
|
||||
error = Cmd0(drv, 0);
|
||||
if (error) {
|
||||
TRACE_1("MMC rst %s\n\r",
|
||||
SD_StringifyRetCode(error));
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
high_capacity = false;
|
||||
error = Cmd1(drv, &high_capacity);
|
||||
if (error) {
|
||||
TRACE_1("MMC oc %s\n\r",
|
||||
SD_StringifyRetCode(error));
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
/* MMC card identification OK */
|
||||
TRACE("MMC\n\r");
|
||||
dev_type = high_capacity ? CARD_MMCHD : CARD_MMC;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev_type == CARD_UNKNOWN) {
|
||||
TRACE("Unknown card\n\r");
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
drv->card.bCardType = dev_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switch card state between STBY and TRAN (or CMD and TRAN)
|
||||
* \param pSd Pointer to a SD card driver instance.
|
||||
* \param address Card address to TRAN, 0 to STBY
|
||||
* \param statCheck Whether to check the status before CMD7.
|
||||
*/
|
||||
uint8_t SdMmcSelect(SdmmcDriver *drv, uint16_t address, uint8_t statCheck)
|
||||
{
|
||||
uint8_t error;
|
||||
uint32_t status, currState;
|
||||
uint32_t targetState = address ? STATUS_TRAN : STATUS_STBY;
|
||||
uint32_t srcState = address ? STATUS_STBY : STATUS_TRAN;
|
||||
|
||||
/* At this stage the Initialization and identification process is achieved
|
||||
* The SD card is supposed to be in Stand-by State */
|
||||
while (statCheck) {
|
||||
error = Cmd13(drv, &status);
|
||||
if (error)
|
||||
return error;
|
||||
if (status & STATUS_READY_FOR_DATA) {
|
||||
currState = status & STATUS_STATE;
|
||||
if (currState == targetState)
|
||||
return 0;
|
||||
if (currState != srcState) {
|
||||
TRACE_ERROR_1("st %lx\n\r", currState);
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch to Transfer state. Select the current SD/MMC
|
||||
* so that SD ACMD6 can process or EXT_CSD can read. */
|
||||
error = Cmd7(drv, address);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decode Trans Speed Value
|
||||
* \param code The trans speed code value.
|
||||
* \param unitCodes Unit list in 10K, 0 as unused value.
|
||||
* \param multiCodes Multiplier list in 1/10, index 1 ~ 15 is valid.
|
||||
*/
|
||||
uint32_t SdmmcDecodeTransSpeed(uint32_t code,
|
||||
const uint16_t * unitCodes, const uint8_t * multiCodes)
|
||||
{
|
||||
uint32_t speed;
|
||||
uint8_t unitI, mulI;
|
||||
|
||||
/* Unit code is valid ? */
|
||||
unitI = code & 0x7;
|
||||
if (unitCodes[unitI] == 0)
|
||||
return 0;
|
||||
|
||||
/* Multi code is valid ? */
|
||||
mulI = (code >> 3) & 0xF;
|
||||
if (multiCodes[mulI] == 0)
|
||||
return 0;
|
||||
|
||||
speed = (uint32_t)unitCodes[unitI] * multiCodes[mulI];
|
||||
return speed;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
#ifndef _CH_SDMMC_LIB_H
|
||||
#define _CH_SDMMC_LIB_H
|
||||
|
||||
#include "sama_sdmmc_conf.h"
|
||||
|
||||
|
||||
/**
|
||||
* \brief SD/MMC card driver structure.
|
||||
* It holds the current command being processed and the SD/MMC card address.
|
||||
*
|
||||
* The first members of this structure may have to follow the DMA alignment
|
||||
* requirements.
|
||||
*/
|
||||
typedef struct _SdCard {
|
||||
|
||||
|
||||
uint8_t *EXT; /**< MMC Extended Device-Specific Data Register
|
||||
* (EXT_CSD). This member may have to follow
|
||||
* the DMA alignment requirements. */
|
||||
uint8_t *SSR; /**< SD Status Register (SSR).
|
||||
* This member may have to follow the DMA
|
||||
* alignment requirements. */
|
||||
uint8_t *SCR; /**< SD CARD Configuration Register (SCR).
|
||||
* This member may have to follow the DMA
|
||||
* alignment requirements. */
|
||||
uint8_t *sandbox1; /**< Multi-purpose temporary buffer.
|
||||
* This member may have to follow the DMA
|
||||
* alignment requirements. */
|
||||
uint8_t *sandbox2; /**< Multi-purpose temporary buffer.
|
||||
* This member may have to follow the DMA
|
||||
* alignment requirements. */
|
||||
|
||||
uint32_t CID[128 / 8 / 4]; /**< Card Identification (CID register) */
|
||||
uint32_t CSD[128 / 8 / 4]; /**< Card-specific data (CSD register) */
|
||||
|
||||
void *pExt; /**< Pointer to extension data for SD/MMC/SDIO */
|
||||
|
||||
uint32_t dwTotalSize; /**< Card total size
|
||||
(0xffffffff to see number of blocks */
|
||||
uint32_t dwNbBlocks; /**< Card total number of blocks */
|
||||
uint16_t wBlockSize; /**< Card block size reported */
|
||||
|
||||
uint16_t wCurrBlockLen; /**< Block length used */
|
||||
uint32_t dwCurrSpeed; /**< Device clock frequency used, in Hz */
|
||||
uint16_t wAddress; /**< Current card address */
|
||||
uint8_t bCardType; /**< SD/MMC/SDIO card type \sa sdmmc_cardtype */
|
||||
uint8_t bCardSigLevel; /**< 0/1/2 for low/ready_for_low/high signaling
|
||||
* level used by the card, respectively. */
|
||||
uint8_t bSpeedMode; /**< Timing mode */
|
||||
uint8_t bBusMode; /**< 1/4/8 bit data bus mode */
|
||||
|
||||
uint8_t bStatus; /**< Unrecovered error */
|
||||
uint8_t bSetBlkCnt; /**< Explicit SET_BLOCK_COUNT command used */
|
||||
uint8_t bStopMultXfer; /**< Explicit STOP_TRANSMISSION command used */
|
||||
} sSdCard;
|
||||
|
||||
|
||||
/**
|
||||
* Sdmmc command operation settings union.
|
||||
*/
|
||||
typedef union _SdmmcCmdOperation {
|
||||
uint16_t wVal;
|
||||
struct _SdmmcOpBm {
|
||||
uint16_t powerON:1, /**< Do power on initialize */
|
||||
sendCmd:1, /**< Send SD/MMC command */
|
||||
xfrData:2, /**< Send/Stop data transfer */
|
||||
respType:3, /**< Response type (1~7) */
|
||||
crcON:1, /**< CRC is used (SPI) */
|
||||
odON:1, /**< Open-Drain is ON (MMC) */
|
||||
ioCmd:1, /**< SDIO command */
|
||||
checkBsy:1; /**< Busy check is ON */
|
||||
} bmBits;
|
||||
} uSdmmcCmdOp;
|
||||
|
||||
/**
|
||||
* Sdmmc command instance.
|
||||
*/
|
||||
typedef struct _SdmmcCommand {
|
||||
|
||||
/** Optional user-provided callback function. */
|
||||
//fSdmmcCallback fCallback;
|
||||
/** Optional argument to the callback function. */
|
||||
void *pArg;
|
||||
|
||||
/** Data buffer. It shall follow the peripheral and DMA alignment
|
||||
* requirements, which are peripheral and driver dependent. */
|
||||
uint8_t *pData;
|
||||
/** Size of data block in bytes. */
|
||||
uint16_t wBlockSize;
|
||||
/** Number of blocks to be transfered */
|
||||
uint16_t wNbBlocks;
|
||||
/** Response buffer. */
|
||||
uint32_t *pResp;
|
||||
|
||||
/** Command argument. */
|
||||
uint32_t dwArg;
|
||||
/** Command operation settings */
|
||||
uSdmmcCmdOp cmdOp;
|
||||
/** Command index */
|
||||
uint8_t bCmd;
|
||||
/** Command return status */
|
||||
volatile uint8_t bStatus;
|
||||
} sSdmmcCommand;
|
||||
|
||||
|
||||
/** SD/MMC Return codes */
|
||||
typedef enum {
|
||||
SDMMC_OK = 0, /**< Operation OK */
|
||||
SDMMC_LOCKED = 1, /**< Failed because driver locked */
|
||||
SDMMC_BUSY = 2, /**< Failed because driver busy */
|
||||
SDMMC_NO_RESPONSE = 3, /**< Failed because card not respond */
|
||||
SDMMC_CHANGED, /**< Setting param changed due to limitation */
|
||||
SDMMC_ERR, /**< Failed with general error */
|
||||
SDMMC_ERR_IO, /**< Failed because of IO error */
|
||||
SDMMC_ERR_RESP, /**< Error reported in response code */
|
||||
SDMMC_NOT_INITIALIZED, /**< Fail to initialize */
|
||||
SDMMC_PARAM, /**< Parameter error */
|
||||
SDMMC_STATE, /**< State error */
|
||||
SDMMC_USER_CANCEL, /**< Canceled by user */
|
||||
SDMMC_NOT_SUPPORTED /**< Command(Operation) not supported */
|
||||
} eSDMMC_RC;
|
||||
|
||||
/**
|
||||
* \addtogroup sdmmc_cardtype SD/MMC Card Types
|
||||
* Here lists the SD/MMC card types.
|
||||
* - Card Type Category Bitmap
|
||||
* - \ref CARD_TYPE_bmHC
|
||||
* - \ref CARD_TYPE_bmSDMMC
|
||||
* - \ref CARD_TYPE_bmUNKNOWN
|
||||
* - \ref CARD_TYPE_bmSD
|
||||
* - \ref CARD_TYPE_bmMMC
|
||||
* - \ref CARD_TYPE_bmSDIO
|
||||
* - Card Types
|
||||
* - \ref CARD_UNKNOWN
|
||||
* - \ref CARD_SD
|
||||
* - \ref CARD_SDHC
|
||||
* - \ref CARD_MMC
|
||||
* - \ref CARD_MMCHD
|
||||
* - \ref CARD_SDIO
|
||||
* - \ref CARD_SDCOMBO
|
||||
* - \ref CARD_SDHCCOMBO
|
||||
* @{*/
|
||||
#define CARD_TYPE_bmHC (1 << 0) /**< Bit for High-Capacity(Density) */
|
||||
#define CARD_TYPE_bmSDMMC (0x3 << 1) /**< Bits mask for SD/MMC */
|
||||
#define CARD_TYPE_bmUNKNOWN (0x0 << 1) /**< Bits for Unknown card */
|
||||
#define CARD_TYPE_bmSD (0x1 << 1) /**< Bits for SD */
|
||||
#define CARD_TYPE_bmMMC (0x2 << 1) /**< Bits for MMC */
|
||||
#define CARD_TYPE_bmSDIO (1 << 3) /**< Bit for SDIO */
|
||||
/** Card can not be identified */
|
||||
#define CARD_UNKNOWN (0)
|
||||
/** SD Card (0x2) */
|
||||
#define CARD_SD (CARD_TYPE_bmSD)
|
||||
/** SD High Capacity Card (0x3) */
|
||||
#define CARD_SDHC (CARD_TYPE_bmSD|CARD_TYPE_bmHC)
|
||||
/** MMC Card (0x4) */
|
||||
#define CARD_MMC (CARD_TYPE_bmMMC)
|
||||
/** MMC High-Density Card (0x5) */
|
||||
#define CARD_MMCHD (CARD_TYPE_bmMMC|CARD_TYPE_bmHC)
|
||||
/** SDIO only card (0x8) */
|
||||
#define CARD_SDIO (CARD_TYPE_bmSDIO)
|
||||
/** SDIO Combo, with SD embedded (0xA) */
|
||||
#define CARD_SDCOMBO (CARD_TYPE_bmSDIO|CARD_SD)
|
||||
/** SDIO Combo, with SDHC embedded (0xB) */
|
||||
#define CARD_SDHCCOMBO (CARD_TYPE_bmSDIO|CARD_SDHC)
|
||||
|
||||
#include "ch_sdmmc_macros.h"
|
||||
#include "ch_sdmmc_trace.h"
|
||||
|
||||
extern const uint16_t sdmmcTransUnits[8];
|
||||
extern const uint8_t sdTransMultipliers[16];
|
||||
extern const uint8_t mmcTransMultipliers[16];
|
||||
extern void SdParamReset(sSdCard * pSd);
|
||||
extern uint32_t SdmmcDecodeTransSpeed(uint32_t code,const uint16_t * unitCodes, const uint8_t * multiCodes);
|
||||
|
||||
|
||||
|
||||
#endif /*_CH_SDMMC_LIB_H*/
|
File diff suppressed because it is too large
Load Diff
|
@ -1,273 +0,0 @@
|
|||
|
||||
#ifndef CH_SDMMC_CMDS_H_
|
||||
#define CH_SDMMC_CMDS_H_
|
||||
|
||||
|
||||
/**
|
||||
* \struct SdCmd6Arg
|
||||
* Argument for SD CMD6
|
||||
*/
|
||||
typedef struct _SdCmd6Arg {
|
||||
uint32_t acc_mode:4, /**< [ 3: 0] function group 1, access mode */
|
||||
cmd_sys:4, /**< [ 7: 4] function group 2, command system */
|
||||
drv_strgth:4, /**< [11: 8] function group 3, driver strength */
|
||||
pwr_limit:4, /**< [15:12] function group 4, power limit */
|
||||
func_grp5:4, /**< [19:16] function group 5, 0xF or 0x0 */
|
||||
func_grp6:4, /**< [23:20] function group 6, 0xF or 0x0 */
|
||||
reserved:7, /**< [30:24] reserved 0 */
|
||||
set:1; /**< [31 ] operation: 0 to check or 1 to set */
|
||||
} SdCmd6Arg, SdSwitchArg;
|
||||
|
||||
|
||||
|
||||
/** \addtogroup sdmmc_struct_cmdarg SD/MMC command arguments
|
||||
* Here lists the command arguments for SD/MMC.
|
||||
* - CMD6 Argument
|
||||
* - \ref MmcCmd6Arg "MMC CMD6"
|
||||
* - \ref SdCmd6Arg "SD CMD6"
|
||||
* - \ref SdioCmd52Arg CMD52
|
||||
* - \ref SdioCmd53Arg CMD53
|
||||
* @{*/
|
||||
/**
|
||||
* \struct MmcCmd6Arg
|
||||
* Argument for MMC CMD6
|
||||
*/
|
||||
typedef struct _MmcCmd6Arg {
|
||||
uint8_t access;
|
||||
uint8_t index;
|
||||
uint8_t value;
|
||||
uint8_t cmdSet;
|
||||
} MmcCmd6Arg, MmcSwitchArg;
|
||||
/**
|
||||
* \struct SdioCmd52Arg
|
||||
* Argument for SDIO CMD52
|
||||
*/
|
||||
typedef struct _SdioCmd52Arg {
|
||||
uint32_t data:8, /**< [ 7: 0] data for writing */
|
||||
stuff0:1, /**< [ 8] reserved */
|
||||
regAddress:17, /**< [25: 9] register address */
|
||||
stuff1:1, /**< [ 26] reserved */
|
||||
rawFlag:1, /**< [ 27] Read after Write flag */
|
||||
functionNum:3, /**< [30:28] Number of the function */
|
||||
rwFlag:1; /**< [ 31] Direction, 1:write, 0:read. */
|
||||
} SdioCmd52Arg, SdioRwDirectArg;
|
||||
|
||||
#define SDMMC_CMD_bmPOWERON (0x1 ) /**< Do Power ON sequence */
|
||||
#define SDMMC_CMD_bmCOMMAND (0x1 << 1) /**< Send command */
|
||||
#define SDMMC_CMD_bmDATAMASK (0x3 << 2) /**< Data operation mask */
|
||||
#define SDMMC_CMD_bmNODATA (0x0 << 2) /**< No data transfer */
|
||||
#define SDMMC_CMD_RX 0x1 /**< data RX */
|
||||
#define SDMMC_CMD_bmDATARX (0x1 << 2) /**< Bits for data RX */
|
||||
#define SDMMC_CMD_TX 0x2 /**< data TX */
|
||||
#define SDMMC_CMD_bmDATATX (0x2 << 2) /**< Bits for data TX */
|
||||
#define SDMMC_CMD_STOPXFR 0x3 /**< data stop */
|
||||
#define SDMMC_CMD_bmSTOPXFR (0x3 << 2) /**< Bits for transfer stop */
|
||||
#define SDMMC_CMD_bmRESPMASK (0x7 << 4) /**< Bits masks response option */
|
||||
#define SDMMC_CMD_bmRESP(R) (((R)&0x7) << 4) /**< Bits setup response type: 1 for R1, 2 for R2, ... 7 for R7 */
|
||||
|
||||
|
||||
|
||||
/** \addtogroup sdmmc_status_bm SD/MMC Status register constants
|
||||
* @{*/
|
||||
#define STATUS_APP_CMD (1UL << 5)
|
||||
#define STATUS_SWITCH_ERROR (1UL << 7)
|
||||
#define STATUS_READY_FOR_DATA (1UL << 8)
|
||||
#define STATUS_IDLE (0UL << 9)
|
||||
#define STATUS_READY (1UL << 9)
|
||||
#define STATUS_IDENT (2UL << 9)
|
||||
#define STATUS_STBY (3UL << 9)
|
||||
#define STATUS_TRAN (4UL << 9)
|
||||
#define STATUS_DATA (5UL << 9)
|
||||
#define STATUS_RCV (6UL << 9)
|
||||
#define STATUS_PRG (7UL << 9)
|
||||
#define STATUS_DIS (8UL << 9)
|
||||
#define STATUS_BTST (9UL << 9)
|
||||
#define STATUS_SLEEP (10UL << 9)
|
||||
#define STATUS_STATE (0xFUL << 9)
|
||||
#define STATUS_ERASE_RESET (1UL << 13)
|
||||
#define STATUS_WP_ERASE_SKIP (1UL << 15)
|
||||
#define STATUS_CIDCSD_OVERWRITE (1UL << 16)
|
||||
#define STATUS_OVERRUN (1UL << 17)
|
||||
#define STATUS_UNERRUN (1UL << 18)
|
||||
#define STATUS_ERROR (1UL << 19)
|
||||
#define STATUS_CC_ERROR (1UL << 20)
|
||||
#define STATUS_CARD_ECC_FAILED (1UL << 21)
|
||||
#define STATUS_ILLEGAL_COMMAND (1UL << 22)
|
||||
#define STATUS_COM_CRC_ERROR (1UL << 23)
|
||||
#define STATUS_UN_LOCK_FAILED (1UL << 24)
|
||||
#define STATUS_CARD_IS_LOCKED (1UL << 25)
|
||||
#define STATUS_WP_VIOLATION (1UL << 26)
|
||||
#define STATUS_ERASE_PARAM (1UL << 27)
|
||||
#define STATUS_ERASE_SEQ_ERROR (1UL << 28)
|
||||
#define STATUS_BLOCK_LEN_ERROR (1UL << 29)
|
||||
#define STATUS_ADDRESS_MISALIGN (1UL << 30)
|
||||
#define STATUS_ADDR_OUT_OR_RANGE (1UL << 31)
|
||||
|
||||
#define STATUS_STOP ((uint32_t)( STATUS_CARD_IS_LOCKED \
|
||||
| STATUS_COM_CRC_ERROR \
|
||||
| STATUS_ILLEGAL_COMMAND \
|
||||
| STATUS_CC_ERROR \
|
||||
| STATUS_ERROR \
|
||||
| STATUS_STATE \
|
||||
| STATUS_READY_FOR_DATA ))
|
||||
|
||||
#define STATUS_WRITE ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
|
||||
| STATUS_ADDRESS_MISALIGN \
|
||||
| STATUS_BLOCK_LEN_ERROR \
|
||||
| STATUS_WP_VIOLATION \
|
||||
| STATUS_CARD_IS_LOCKED \
|
||||
| STATUS_COM_CRC_ERROR \
|
||||
| STATUS_ILLEGAL_COMMAND \
|
||||
| STATUS_CC_ERROR \
|
||||
| STATUS_ERROR \
|
||||
| STATUS_ERASE_RESET \
|
||||
| STATUS_STATE \
|
||||
| STATUS_READY_FOR_DATA ))
|
||||
|
||||
#define STATUS_READ ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
|
||||
| STATUS_ADDRESS_MISALIGN \
|
||||
| STATUS_BLOCK_LEN_ERROR \
|
||||
| STATUS_CARD_IS_LOCKED \
|
||||
| STATUS_COM_CRC_ERROR \
|
||||
| STATUS_ILLEGAL_COMMAND \
|
||||
| STATUS_CARD_ECC_FAILED \
|
||||
| STATUS_CC_ERROR \
|
||||
| STATUS_ERROR \
|
||||
| STATUS_ERASE_RESET \
|
||||
| STATUS_STATE \
|
||||
| STATUS_READY_FOR_DATA ))
|
||||
|
||||
#define STATUS_SD_SWITCH ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
|
||||
| STATUS_CARD_IS_LOCKED \
|
||||
| STATUS_COM_CRC_ERROR \
|
||||
| STATUS_ILLEGAL_COMMAND \
|
||||
| STATUS_CARD_ECC_FAILED \
|
||||
| STATUS_CC_ERROR \
|
||||
| STATUS_ERROR \
|
||||
| STATUS_UNERRUN \
|
||||
| STATUS_OVERRUN \
|
||||
/*| STATUS_STATE*/))
|
||||
|
||||
#define STATUS_MMC_SWITCH ((uint32_t)( STATUS_CARD_IS_LOCKED \
|
||||
| STATUS_COM_CRC_ERROR \
|
||||
| STATUS_ILLEGAL_COMMAND \
|
||||
| STATUS_CC_ERROR \
|
||||
| STATUS_ERROR \
|
||||
| STATUS_ERASE_RESET \
|
||||
/*| STATUS_STATE*/ \
|
||||
/*| STATUS_READY_FOR_DATA*/ \
|
||||
| STATUS_SWITCH_ERROR ))
|
||||
|
||||
#define SD_OCR_S18A (1ul << 24) /**< Switching to 1.8V signaling level Accepted */
|
||||
#define SDIO_OCR_MP (0x1ul << 27) /**< SDIO: Memory present */
|
||||
#define SDIO_OCR_NF (0x3ul << 28) /**< SDIO: Number of functions */
|
||||
#define MMC_OCR_ACCESS_MODE (0x3ul << 29) /**< MMC: Access mode, 0x2 is sector mode */
|
||||
#define MMC_OCR_ACCESS_BYTE (0x0 << 29) /**< MMC: Byte access mode */
|
||||
#define MMC_OCR_ACCESS_SECTOR (0x2ul << 29) /**< MMC: Sector access mode */
|
||||
#define SD_OCR_UHS_II (1ul << 29) /**< SD: UHS-II Card Status */
|
||||
#define SD_OCR_CCS (1ul << 30) /**< SD: Card Capacity Status */
|
||||
#define SD_OCR_BUSYN (1ul << 31) /**< SD/MMC: Busy Status */
|
||||
|
||||
|
||||
/** \addtogroup sdmmc_sd_status SD/MMC status fields
|
||||
* @{
|
||||
*/
|
||||
/** SSR (SD Status) access macros (512 bits, 16 * 32 bits, 64 * 8 bits). */
|
||||
#define SD_ST(pSt, field, bits) SD_GetField(pSt, 512, field, bits)
|
||||
#define SD_SSR_DAT_BUS_WIDTH(pSt) (uint8_t)SD_ST(pSt, 510, 2) /**< Bus width, 00: default, 10:4-bit */
|
||||
#define SD_SSR_DATA_BUS_WIDTH_1BIT 0x0 /**< 1-bit bus width */
|
||||
#define SD_SSR_DATA_BUS_WIDTH_4BIT 0x2 /**< 4-bit bus width */
|
||||
#define SD_SSR_SECURED_MODE(pSt) (uint8_t)SD_ST(pSt, 509, 1) /**< Secured Mode */
|
||||
#define SD_SSR_CARD_TYPE(pSt) (uint16_t)SD_ST(pSt, 480, 16)
|
||||
#define SD_SSR_CARD_TYPE_RW 0x0000 /**< Regular SD R/W Card */
|
||||
#define SD_SSR_CARD_TYPE_ROM 0x0001 /**< SD ROM Card */
|
||||
#define SD_SSR_CARD_TYPE_OTP 0x0002 /**< OTP SD Card */
|
||||
#define SD_SSR_SIZE_OF_PROTECTED_AREA(pSt) SD_ST(pSt, 448, 32) /**< STD: ThisSize*Multi*BlockLen, HC: Size in bytes */
|
||||
#define SD_SSR_SPEED_CLASS(pSt) (uint8_t)SD_ST(pSt, 440, 8) /**< Speed Class, value can be calculated by Pw/2 */
|
||||
#define SD_SSR_SPEED_CLASS_0 0
|
||||
#define SD_SSR_SPEED_CLASS_2 1 // >= 2MB/s
|
||||
#define SD_SSR_SPEED_CLASS_4 2 // >= 4MB/s
|
||||
#define SD_SSR_SPEED_CLASS_6 3 // >= 6MB/s
|
||||
#define SD_SSR_SPEED_CLASS_10 4 // >= 10MB/s
|
||||
#define SD_SSR_PERFORMANCE_MOVE(pSt) (uint8_t)SD_ST(pSt, 432, 8) /**< 8-bit, by 1MB/s step. */
|
||||
#define SD_SSR_AU_SIZE(pSt) (uint8_t)SD_ST(pSt, 428, 4) /**< AU Size, in power of 2 from 16KB */
|
||||
#define SD_SSR_AU_SIZE_16K 1
|
||||
#define SD_SSR_AU_SIZE_32K 2
|
||||
#define SD_SSR_AU_SIZE_64K 3
|
||||
#define SD_SSR_AU_SIZE_128K 4
|
||||
#define SD_SSR_AU_SIZE_256K 5
|
||||
#define SD_SSR_AU_SIZE_512K 6
|
||||
#define SD_SSR_AU_SIZE_1M 7
|
||||
#define SD_SSR_AU_SIZE_2M 8
|
||||
#define SD_SSR_AU_SIZE_4M 9
|
||||
#define SD_SSR_AU_SIZE_8M 0xa
|
||||
#define SD_SSR_AU_SIZE_12M 0xb
|
||||
#define SD_SSR_AU_SIZE_16M 0xc
|
||||
#define SD_SSR_AU_SIZE_24M 0xd
|
||||
#define SD_SSR_AU_SIZE_32M 0xe
|
||||
#define SD_SSR_AU_SIZE_64M 0xf
|
||||
#define SD_SSR_ERASE_SIZE(pSt) (uint16_t)SD_ST(pSt, 408, 16) /**< 16-bit, number of AUs erased. */
|
||||
#define SD_SSR_ERASE_TIMEOUT(pSt) (uint8_t)SD_ST(pSt, 402, 6) /**< Timeout value for erasing areas */
|
||||
#define SD_SSR_ERASE_OFFSET(pSt) (uint8_t)SD_ST(pSt, 400, 2) /**< Fixed offset value added to erase time */
|
||||
#define SD_SSR_UHS_SPEED_GRADE(pSt) (uint8_t)SD_ST(pSt, 396, 4) /**< Speed Grade for UHS mode */
|
||||
#define SD_SSR_SPEED_GRADE_0 0x0
|
||||
#define SD_SSR_SPEED_GRADE_1 0x1
|
||||
#define SD_SSR_SPEED_GRADE_3 0x3
|
||||
#define SD_SSR_UHS_AU_SIZE(pSt) (uint8_t)SD_ST(pSt, 392, 4) /**< Size of AU for UHS mode */
|
||||
#define SD_SSR_UHS_AU_SIZE_UNDEF 0
|
||||
#define SD_SSR_UHS_AU_SIZE_1M 0x7
|
||||
#define SD_SSR_UHS_AU_SIZE_2M 0x8
|
||||
#define SD_SSR_UHS_AU_SIZE_4M 0x9
|
||||
#define SD_SSR_UHS_AU_SIZE_8M 0xa
|
||||
#define SD_SSR_UHS_AU_SIZE_12M 0xb
|
||||
#define SD_SSR_UHS_AU_SIZE_16M 0xc
|
||||
#define SD_SSR_UHS_AU_SIZE_24M 0xd
|
||||
#define SD_SSR_UHS_AU_SIZE_32M 0xe
|
||||
#define SD_SSR_UHS_AU_SIZE_64M 0xf
|
||||
|
||||
|
||||
extern uint8_t tuneSampling(SdmmcDriver *driver);
|
||||
extern uint8_t CancelCommand(SdmmcDriver *driver);
|
||||
extern uint8_t CmdPowerOn(SdmmcDriver *drv);
|
||||
extern uint8_t SdCmd6(SdmmcDriver *drv,
|
||||
const SdCmd6Arg * pSwitchArg, uint8_t * pStatus, uint32_t * pResp);
|
||||
extern uint8_t SdCmd8(SdmmcDriver *drv, uint8_t supplyVoltage);
|
||||
extern uint8_t Acmd6(SdmmcDriver *pSd, uint8_t busWidth);
|
||||
extern uint8_t Acmd13(SdmmcDriver *drv, uint8_t * pSSR, uint32_t * pResp);
|
||||
extern uint8_t Acmd41(SdmmcDriver *drv, bool * low_sig_lvl, bool * hc);
|
||||
extern uint8_t Acmd51(SdmmcDriver *drv, uint8_t * pSCR, uint32_t * pResp);
|
||||
extern uint8_t Cmd0(SdmmcDriver *drv, uint8_t arg);
|
||||
extern uint8_t Cmd1(SdmmcDriver *drv, bool * hc);
|
||||
extern uint8_t Cmd2(SdmmcDriver *drv);
|
||||
extern uint8_t Cmd3(SdmmcDriver *drv);
|
||||
extern uint8_t Cmd5(SdmmcDriver *drv, uint32_t * pIo);
|
||||
extern uint8_t Cmd7(SdmmcDriver *drv, uint16_t address);
|
||||
extern uint8_t Cmd9(SdmmcDriver *drv);
|
||||
extern uint8_t Cmd11(SdmmcDriver *drv, uint32_t * pStatus);
|
||||
extern uint8_t Cmd12(SdmmcDriver *drv, uint32_t * pStatus);
|
||||
extern uint8_t Cmd13(SdmmcDriver *drv, uint32_t * pStatus);
|
||||
extern uint8_t Cmd14(SdmmcDriver *drv, uint8_t * pData, uint8_t len, uint32_t * pStatus);
|
||||
|
||||
extern uint8_t Cmd16(SdmmcDriver *drv, uint16_t blkLen);
|
||||
extern uint8_t Cmd17(SdmmcDriver *drv,
|
||||
uint8_t * pData,
|
||||
uint32_t address, uint32_t * pStatus);
|
||||
extern uint8_t Cmd18(SdmmcDriver *drv,uint16_t * nbBlock,uint8_t * pData,uint32_t address, uint32_t * pStatus);
|
||||
extern uint8_t Cmd19(SdmmcDriver *drv, uint8_t * pData, uint8_t len, uint32_t * pStatus);
|
||||
extern uint8_t Cmd23(SdmmcDriver *drv, uint8_t write, uint32_t blocks, uint32_t * pStatus);
|
||||
extern uint8_t Cmd24(SdmmcDriver *drv,
|
||||
uint8_t * pData,
|
||||
uint32_t address, uint32_t * pStatus);
|
||||
extern uint8_t Cmd25(SdmmcDriver *drv,
|
||||
uint16_t * nbBlock,
|
||||
uint8_t * pData,
|
||||
uint32_t address, uint32_t * pStatus);
|
||||
extern uint8_t Cmd52(SdmmcDriver *drv,uint8_t wrFlag,uint8_t funcNb, uint8_t rdAfterWr, uint32_t addr, uint32_t * pIoData);
|
||||
|
||||
extern uint8_t Cmd55(SdmmcDriver *drv, uint16_t cardAddr);
|
||||
|
||||
extern uint8_t MmcCmd8(SdmmcDriver *drv);
|
||||
extern uint8_t MmcCmd6(SdmmcDriver *drv, const void *pSwitchArg, uint32_t * pResp);
|
||||
|
||||
|
||||
#endif /* CH_SDMMC_CMDS_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,384 +0,0 @@
|
|||
#ifndef CH_SDMMC_DEVICE_H_
|
||||
#define CH_SDMMC_DEVICE_H_
|
||||
|
||||
|
||||
/** \addtogroup sdmmc_ocr_acc SD/MMC OCR register fields (SD 2.0 & MMC 4.3)
|
||||
* @{
|
||||
*/
|
||||
#define SD_OCR_VDD_LOW (1ul << 7) /**< SD: Reserved for Low Voltage Range */
|
||||
#define MMC_OCR_VDD_170_195 (1ul << 7) /**< MMC: 1.7 ~ 1.95V, Dual vol and eMMC is 1 */
|
||||
#define MMC_OCR_VDD_200_270 (0x7Ful << 8) /**< MMC: 2.0 ~ 2.7 V */
|
||||
#define SD_OCR_VDD_20_21 (1ul << 8)
|
||||
#define SD_OCR_VDD_21_22 (1ul << 9)
|
||||
#define SD_OCR_VDD_22_23 (1ul << 10)
|
||||
#define SD_OCR_VDD_23_24 (1ul << 11)
|
||||
#define SD_OCR_VDD_24_25 (1ul << 12)
|
||||
#define SD_OCR_VDD_25_26 (1ul << 13)
|
||||
#define SD_OCR_VDD_26_27 (1ul << 14)
|
||||
#define SD_OCR_VDD_27_28 (1ul << 15)
|
||||
#define SD_OCR_VDD_28_29 (1ul << 16)
|
||||
#define SD_OCR_VDD_29_30 (1ul << 17)
|
||||
#define SD_OCR_VDD_30_31 (1ul << 18)
|
||||
#define SD_OCR_VDD_31_32 (1ul << 19)
|
||||
#define SD_OCR_VDD_32_33 (1ul << 20)
|
||||
#define SD_OCR_VDD_33_34 (1ul << 21)
|
||||
#define SD_OCR_VDD_34_35 (1ul << 22)
|
||||
#define SD_OCR_VDD_35_36 (1ul << 23)
|
||||
|
||||
/**
|
||||
* sdmmc_speedmode SD/MMC Bus speed modes
|
||||
* Here lists the MMC, e.MMC and SD bus speed modes.
|
||||
*/
|
||||
#define SDMMC_TIM_MMC_BC (0x00)
|
||||
#define SDMMC_TIM_MMC_HS_SDR (0x01)
|
||||
#define SDMMC_TIM_MMC_HS_DDR (0x02)
|
||||
#define SDMMC_TIM_MMC_HS200 (0x03)
|
||||
#define SDMMC_TIM_SD_DS (0x10)
|
||||
#define SDMMC_TIM_SD_HS (0x11)
|
||||
#define SDMMC_TIM_SD_SDR12 (0x12)
|
||||
#define SDMMC_TIM_SD_SDR25 (0x13)
|
||||
#define SDMMC_TIM_SD_SDR50 (0x14)
|
||||
#define SDMMC_TIM_SD_DDR50 (0x15)
|
||||
#define SDMMC_TIM_SD_SDR104 (0x16)
|
||||
|
||||
|
||||
/**
|
||||
* \addtogroup sdmmc_powermode SD/MMC power supply modes
|
||||
* Here we list the voltage level configurations we may apply when supplying
|
||||
* power to the device.
|
||||
* @{*/
|
||||
#define SDMMC_PWR_OFF (0)
|
||||
#define SDMMC_PWR_STD (1)
|
||||
#define SDMMC_PWR_STD_VDD_LOW_IO (2)
|
||||
|
||||
/** SD/MMC Low Level IO Control: Check busy.
|
||||
Must implement for low level driver busy check.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_BUSY_CHECK, (uint32_t)pBusyFlag) */
|
||||
#define SDMMC_IOCTL_BUSY_CHECK 0x0
|
||||
/** SD/MMC Low Level IO Control: Power control.
|
||||
Recommended for SD/MMC/SDIO power control.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_POWER, (uint32_t)ON/OFF) */
|
||||
#define SDMMC_IOCTL_POWER 0x1
|
||||
/** SD/MMC Low Level IO Control: Cancel command.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_CANCEL_CMD, NULL) */
|
||||
#define SDMMC_IOCTL_CANCEL_CMD 0x2
|
||||
/** SD/MMC Low Level IO Control: Reset & disable HW.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_RESET, NULL) */
|
||||
#define SDMMC_IOCTL_RESET 0x3
|
||||
/** SD/MMC Low Level IO Control: Set clock frequency, return applied frequency
|
||||
Recommended for clock selection
|
||||
IOCtrl(pSd, SDMMC_IOCTL_SET_CLOCK, (uint32_t*)pIoFreq) */
|
||||
#define SDMMC_IOCTL_SET_CLOCK 0x11
|
||||
/** SD/MMC Low Level IO Control: Set bus mode, return applied mode
|
||||
Recommended for bus mode selection
|
||||
IOCtrl(pSd, SDMMC_IOCTL_SET_BUSMODE, (uint32_t*)pIoBusMode) */
|
||||
#define SDMMC_IOCTL_SET_BUSMODE 0x12
|
||||
/** SD/MMC Low Level IO Control: Select one of the SDMMC_TIM_x timing modes.
|
||||
Returns the effective mode, further to this operation.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_SET_HSMODE, (uint32_t*)pIoTimingMode) */
|
||||
#define SDMMC_IOCTL_SET_HSMODE 0x13
|
||||
/** SD/MMC Low Level IO Control: Set Boot mode */
|
||||
#define SDMMC_IOCTL_SET_BOOTMODE 0x14
|
||||
/** SD/MMC Low Level IO Control: Enable or disable implicit SET_BLOCK_COUNT
|
||||
command, return applied mode.
|
||||
Recommended with devices that support the SET_BLOCK_COUNT command.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_SET_LENPREFIX, (uint32_t*)pIoLenPrefix) */
|
||||
#define SDMMC_IOCTL_SET_LENPREFIX 0x15
|
||||
/** SD/MMC Low Level IO Control: Get clock frequency */
|
||||
#define SDMMC_IOCTL_GET_CLOCK 0x21
|
||||
/** SD/MMC Low Level IO Control: Bus mode */
|
||||
#define SDMMC_IOCTL_GET_BUSMODE 0x22
|
||||
/** SD/MMC Low Level IO Control: Query whether the driver supports the specified
|
||||
SDMMC_TIM_x timing mode. */
|
||||
#define SDMMC_IOCTL_GET_HSMODE 0x23
|
||||
/** SD/MMC Low Level IO Control: Boot mode */
|
||||
#define SDMMC_IOCTL_GET_BOOTMODE 0x24
|
||||
/** SD/MMC Low Level IO Control: Query driver capability, whether the driver
|
||||
implicitly sends the STOP_TRANSMISSION command when multiple-block data
|
||||
transfers complete successfully.
|
||||
IOCtrl(pSd, SDMMC_IOCTL_GET_XFERCOMPL, (uint32_t*)pOAutoXferCompletion) */
|
||||
#define SDMMC_IOCTL_GET_XFERCOMPL 0x25
|
||||
/** SD/MMC Low Level IO Control: Query whether a device is detected in this slot
|
||||
IOCtrl(pSd, SDMMC_IOCTL_GET_DEVICE, (uint32_t*)pODetected) */
|
||||
#define SDMMC_IOCTL_GET_DEVICE 0x26
|
||||
/** SD/MMC Low Level IO Control: Query whether the card is writeprotected
|
||||
or not by mechanical write protect switch */
|
||||
#define SDMMC_IOCTL_GET_WP 0x27
|
||||
/** @}*/
|
||||
|
||||
#define SD_IFC_CHK_PATTERN_Pos 0 /**< Check pattern */
|
||||
#define SD_IFC_CHK_PATTERN_Msk (0xffu << SD_IFC_CHK_PATTERN_Pos)
|
||||
#define SD_IFC_CHK_PATTERN_STD (0xaau << 0)
|
||||
#define SD_IFC_VHS_Pos 8 /**< Host Supplied Voltage range */
|
||||
#define SD_IFC_VHS_Msk (0xfu << SD_IFC_VHS_Pos)
|
||||
#define SD_IFC_VHS_27_36 (0x1u << 8)
|
||||
#define SD_IFC_VHS_LOW (0x2u << 8)
|
||||
|
||||
/** Get u8 from byte pointed data area */
|
||||
#define SD_U8(pD, nBytes, iByte) ( ((uint8_t*)(pD))[(iByte)] )
|
||||
/** Get u16 from data area */
|
||||
#define SD_U16(pD, nBytes, iByte) \
|
||||
( (uint16_t)((uint8_t*)(pD))[(iByte)] |\
|
||||
(uint16_t)((uint8_t*)(pD))[(iByte) + 1] << 8 )
|
||||
/**Get u32 from data area */
|
||||
#define SD_U32(pD, nBytes, iByte) \
|
||||
( (uint32_t)((uint8_t*)(pD))[(iByte)] |\
|
||||
(uint32_t)((uint8_t*)(pD))[(iByte) + 1] << 8 |\
|
||||
(uint32_t)((uint8_t*)(pD))[(iByte) + 2] << 16 |\
|
||||
(uint32_t)((uint8_t*)(pD))[(iByte) + 3] << 24 )
|
||||
|
||||
|
||||
|
||||
|
||||
/** \addtogroup mmc_ext_csd MMC Extended CSD byte fields
|
||||
* @{
|
||||
*/
|
||||
/** MMC Extended CSD access macro: get one byte (512 bytes). */
|
||||
#define MMC_EXT8(p, i) SD_U8(p, 512, i)
|
||||
/** MMC Extended CSD access macro: get one word (512 bytes). */
|
||||
#define MMC_EXT32(p, i) SD_U32(p, 512, i)
|
||||
#define MMC_EXT_S_CMD_SET_I 504 /**< Supported Command Sets slice */
|
||||
#define MMC_EXT_S_CMD_SET(p) MMC_EXT8(p, MMC_EXT_S_CMD_SET_I)
|
||||
#define MMC_EXT_PWR_CL_DDR_52_360_I 239 /**< Power Class for 52MHz DDR @ 3.6V */
|
||||
#define MMC_EXT_PWR_CL_DDR_52_360(p) MMC_EXT8(p, MMC_EXT_PWR_CL_DDR_52_360_I)
|
||||
#define MMC_EXT_PWR_CL_200_195_I 237 /**< Power Class for 200MHz HS200 @ VCCQ=1.95V VCC=3.6V */
|
||||
#define MMC_EXT_PWR_CL_200_195(p) MMC_EXT8(p, MMC_EXT_PWR_CL_200_195_I)
|
||||
#define MMC_EXT_BOOT_INFO_I 228 /**< Boot information slice */
|
||||
#define MMC_EXT_BOOT_INFO(p) MMC_EXT8(p, MMC_EXT_BOOT_INFO_I)
|
||||
#define MMC_EXT_BOOT_SIZE_MULTI_I 226 /**< Boot partition size slice */
|
||||
#define MMC_EXT_BOOT_SIZE_MULTI(p) MMC_EXT8(p, MMC_EXT_BOOT_SIZE_MULTI_I)
|
||||
#define MMC_EXT_ACC_SIZE_I 225 /**< Access size slice */
|
||||
#define MMC_EXT_ACC_SIZE(p) MMC_EXT8(p, MMC_EXT_ACC_SIZE_I)
|
||||
#define MMC_EXT_HC_ERASE_GRP_SIZE_I 224 /**< High-capacity erase time unit size slice */
|
||||
#define MMC_EXT_HC_ERASE_GRP_SIZE(p) MMC_EXT8(p, MMC_EXT_HC_ERASE_GRP_SIZE_I)
|
||||
#define MMC_EXT_ERASE_TIMEOUT_MULT_I 223 /**< High-capacity erase timeout slice */
|
||||
#define MMC_EXT_ERASE_TIMEOUT_MULT(p) MMC_EXT8(p, MMC_EXT_ERASE_TIMEOUT_MULT_I)
|
||||
#define MMC_EXT_REL_WR_SEC_C_I 222 /**< Reliable write sector count slice */
|
||||
#define MMC_EXT_REL_WR_SEC_C(p) MMC_EXT8(p, MMC_EXT_REL_WR_SEC_C_I)
|
||||
#define MMC_EXT_HC_WP_GRP_SIZE_I 221 /**< High-capacity write protect group size slice */
|
||||
#define MMC_EXT_HC_WP_GRP_SIZE(p) MMC_EXT8(p, MMC_EXT_HC_WP_GRP_SIZE_I)
|
||||
#define MMC_EXT_S_C_VCC_I 220 /**< Sleep current (VCC) */
|
||||
#define MMC_EXT_S_C_VCC(p) MMC_EXT8(p, MMC_EXT_S_C_VCC_I)
|
||||
#define MMC_EXT_S_C_VCCQ_I 219 /**< Sleep current (VCC) */
|
||||
#define MMC_EXT_S_C_VCCQ(p) MMC_EXT8(p, MMC_EXT_S_C_VCCQ_I)
|
||||
#define MMC_EXT_S_A_TIMEOUT_I 217 /**< Sleep current (VCCQ) */
|
||||
#define MMC_EXT_S_A_TIMEOUT(p) MMC_EXT8(p, MMC_EXT_S_A_TIMEOUT_I)
|
||||
#define MMC_EXT_SEC_COUNT_I 212 /**< Sector Count slice */
|
||||
#define MMC_EXT_SEC_COUNT(p) MMC_EXT32(p, MMC_EXT_SEC_COUNT_I)
|
||||
#define MMC_EXT_MIN_PERF_W_8_52_I 210 /**< Minimum Write Performance for 8bit @ 52MHz */
|
||||
#define MMC_EXT_MIN_PERF_W_8_52(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_W_8_52_I)
|
||||
#define MMC_EXT_MIN_PERF_R_8_52_I 209 /**< Minimum Read Performance for 8bit @ 52MHz */
|
||||
#define MMC_EXT_MIN_PERF_R_8_52(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_R_8_52_I)
|
||||
#define MMC_EXT_MIN_PERF_W_8_26_4_52_I 208 /**< Minimum Write Performance for 8bit @ 26MHz or 4bit @ 52MHz */
|
||||
#define MMC_EXT_MIN_PERF_W_8_26_4_52(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_W_8_26_4_52_I)
|
||||
#define MMC_EXT_MIN_PERF_R_8_26_4_52_I 207 /**< Minimum Read Performance for 8bit @ 26MHz or 4bit @ 52MHz */
|
||||
#define MMC_EXT_MIN_PERF_R_8_26_4_52(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_R_8_26_4_52_I)
|
||||
#define MMC_EXT_MIN_PERF_W_4_26_I 206 /**< Minimum Write Performance for 4bit @ 26MHz */
|
||||
#define MMC_EXT_MIN_PERF_W_4_26(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_W_4_26_I)
|
||||
#define MMC_EXT_MIN_PERF_R_4_26_I 205 /**< Minimum Read Performance for 4bit @ 26MHz */
|
||||
#define MMC_EXT_MIN_PERF_R_4_26(p) MMC_EXT8(p, MMC_EXT_MIN_PERF_R_4_26_I)
|
||||
#define MMC_EXT_PWR_CL_26_360_I 203 /**< Power Class for 26MHz @ 3.6V */
|
||||
#define MMC_EXT_PWR_CL_26_360(p) MMC_EXT8(p, MMC_EXT_PWR_CL_26_360_I)
|
||||
#define MMC_EXT_PWR_CL_52_360_I 202 /**< Power Class for 52MHz @ 3.6V */
|
||||
#define MMC_EXT_PWR_CL_52_360(p) MMC_EXT8(p, MMC_EXT_PWR_CL_52_360_I)
|
||||
#define MMC_EXT_PWR_CL_26_195_I 201 /**< Power Class for 26MHz @ 1.95V */
|
||||
#define MMC_EXT_PWR_CL_26_195(p) MMC_EXT8(p, MMC_EXT_PWR_CL_26_195_I)
|
||||
#define MMC_EXT_PWR_CL_52_195_I 200 /**< Power Class for 52MHz @ 1.95V */
|
||||
#define MMC_EXT_PWR_CL_52_195(p) MMC_EXT8(p, MMC_EXT_PWR_CL_52_195_I)
|
||||
#define MMC_EXT_DRV_STRENGTH_I 197 /**< Supported I/O driver strength types */
|
||||
#define MMC_EXT_DRV_STRENGTH(p) MMC_EXT8(p, MMC_EXT_DRV_STRENGTH_I)
|
||||
#define MMC_EXT_CARD_TYPE_I 196 /**< Card Type */
|
||||
#define MMC_EXT_CARD_TYPE(p) MMC_EXT8(p, MMC_EXT_CARD_TYPE_I)
|
||||
#define MMC_EXT_CSD_STRUCTURE_I 194 /**< CSD Structure Version */
|
||||
#define MMC_EXT_CSD_STRUCTURE(p) MMC_EXT8(p, MMC_EXT_CSD_STRUCTURE_I)
|
||||
#define MMC_EXT_EXT_CSD_REV_I 192 /**< Extended CSD Revision */
|
||||
#define MMC_EXT_EXT_CSD_REV(p) MMC_EXT8(p, MMC_EXT_EXT_CSD_REV_I)
|
||||
#define MMC_EXT_CMD_SET_I 191 /**< Command Set */
|
||||
#define MMC_EXT_CMD_SET(p) MMC_EXT8(p, MMC_EXT_CMD_SET_I)
|
||||
#define MMC_EXT_CMD_SET_REV_I 189 /**< Command Set Revision */
|
||||
#define MMC_EXT_CMD_SET_REV(p) MMC_EXT8(p, MMC_EXT_CMD_SET_REV_I)
|
||||
#define MMC_EXT_POWER_CLASS_I 187 /**< Power Class */
|
||||
#define MMC_EXT_POWER_CLASS(p) MMC_EXT8(p, MMC_EXT_POWER_CLASS_I)
|
||||
#define MMC_EXT_HS_TIMING_I 185 /**< High Speed Interface Timing */
|
||||
#define MMC_EXT_HS_TIMING(p) MMC_EXT8(p, MMC_EXT_HS_TIMING_I)
|
||||
#define MMC_EXT_HS_TIMING_HS400 0x3
|
||||
#define MMC_EXT_HS_TIMING_HS200 0x2
|
||||
#define MMC_EXT_HS_TIMING_EN 0x1
|
||||
#define MMC_EXT_HS_TIMING_DIS 0x0
|
||||
#define MMC_EXT_HS_TIMING_40R 0x40
|
||||
#define MMC_EXT_HS_TIMING_100R 0x30
|
||||
#define MMC_EXT_HS_TIMING_66R 0x20
|
||||
#define MMC_EXT_HS_TIMING_33R 0x10
|
||||
#define MMC_EXT_HS_TIMING_50R 0x00
|
||||
#define MMC_EXT_BUS_WIDTH_I 183 /**< Bus Width Mode */
|
||||
#define MMC_EXT_BUS_WIDTH(p) MMC_EXT8(p, MMC_EXT_BUS_WIDTH_I)
|
||||
#define MMC_EXT_BUS_WIDTH_1BIT 0
|
||||
#define MMC_EXT_BUS_WIDTH_4BITS 1
|
||||
#define MMC_EXT_BUS_WIDTH_8BITS 2
|
||||
#define MMC_EXT_BUS_WIDTH_DDR 0x4
|
||||
#define MMC_EXT_ERASED_MEM_CONT_I 181 /**< Erased Memory Content */
|
||||
#define MMC_EXT_ERASED_MEM_CONT(p) MMC_EXT8(p, MMC_EXT_ERASED_MEM_CONT_I)
|
||||
#define MMC_EXT_BOOT_CONFIG_I 179 /**< Boot configuration slice */
|
||||
#define MMC_EXT_BOOT_CONFIG(p) MMC_EXT8(p, MMC_EXT_BOOT_CONFIG_I)
|
||||
#define MMC_EXT_BOOT_BUS_WIDTH_I 177 /**< Boot bus width slice */
|
||||
#define MMC_EXT_BOOT_BUS_WIDTH(p) MMC_EXT8(p, MMC_EXT_BOOT_BUS_WIDTH_I)
|
||||
#define MMC_EXT_ERASE_GROUP_DEF_I 175 /**< High-density erase group definition */
|
||||
#define MMC_EXT_ERASE_GROUP_DEF(p) MMC_EXT8(p, MMC_EXT_ERASE_GROUP_DEF_I)
|
||||
#define MMC_EXT_BOOT_WP_STATUS_I 174 /**< Current protection status of the boot partitions */
|
||||
#define MMC_EXT_BOOT_WP_STATUS(p) MMC_EXT8(p, MMC_EXT_BOOT_WP_STATUS_I)
|
||||
#define MMC_EXT_DATA_SECTOR_SIZE_I 61 /**< Current sector size */
|
||||
#define MMC_EXT_DATA_SECTOR_SIZE(p) MMC_EXT8(p, MMC_EXT_DATA_SECTOR_SIZE_I)
|
||||
#define MMC_EXT_DATA_SECT_512B 0
|
||||
#define MMC_EXT_DATA_SECT_4KIB 1
|
||||
|
||||
|
||||
|
||||
#define SD_BITS32(pDw, nbits, ibit, bits) \
|
||||
( (((uint32_t*)(pDw))[(nbits)/32-(ibit)/32-1] >> ((ibit)%32)) & ((uint32_t)(1ul << (bits)) - 1 ) )
|
||||
|
||||
|
||||
/** \addtogroup sdmmc_cid_acc SD/MMC CID register fields
|
||||
* @{
|
||||
*/
|
||||
/** CID register access (128 bits, 16 * 8 bits, 4 * 32 bits) */
|
||||
#define SD_CID(pCid, field, bits) SD_BITS32(pCid, 128, field, bits)
|
||||
#define SD_CID_MID(pCid) (uint8_t)SD_CID(pCid, 120, 8) /**< Manufacture ID */
|
||||
#define eMMC_CID_CBX(pCid) (uint8_t)SD_CID(pCid, 112, 2) /**< eMMC BGA(01)/CARD(00) */
|
||||
#define SD_CID_OID1(pCid) (uint8_t)SD_CID(pCid, 112, 8) /**< OEM/App ID Byte 1 */
|
||||
#define SD_CID_OID0(pCid) (uint8_t)SD_CID(pCid, 104, 8) /**< OEM/App ID Byte 0 */
|
||||
#define MMC_CID_OID(pCid) (uint16_t)SD_CID(pCid, 104, 16) /**< MMC OEM/App ID */
|
||||
#define eMMC_CID_OID(pCid) (uint8_t)SD_CID(pCid, 104, 8) /**< MMC v4.3+ OEM/App ID */
|
||||
#define SD_CID_PNM4(pCid) (uint8_t)SD_CID(pCid, 96, 8) /**< Product name byte 4 */
|
||||
#define SD_CID_PNM3(pCid) (uint8_t)SD_CID(pCid, 88, 8) /**< Product name byte 3 */
|
||||
#define SD_CID_PNM2(pCid) (uint8_t)SD_CID(pCid, 80, 8) /**< Product name byte 2 */
|
||||
#define SD_CID_PNM1(pCid) (uint8_t)SD_CID(pCid, 72, 8) /**< Product name byte 1 */
|
||||
#define SD_CID_PNM0(pCid) (uint8_t)SD_CID(pCid, 64, 8) /**< Product name byte 0 */
|
||||
#define MMC_CID_PNM5(pCid) (uint8_t)SD_CID(pCid, 96, 8) /**< Product name byte 5 */
|
||||
#define MMC_CID_PNM4(pCid) (uint8_t)SD_CID(pCid, 88, 8) /**< Product name byte 4 */
|
||||
#define MMC_CID_PNM3(pCid) (uint8_t)SD_CID(pCid, 80, 8) /**< Product name byte 3 */
|
||||
#define MMC_CID_PNM2(pCid) (uint8_t)SD_CID(pCid, 72, 8) /**< Product name byte 2 */
|
||||
#define MMC_CID_PNM1(pCid) (uint8_t)SD_CID(pCid, 64, 8) /**< Product name byte 1 */
|
||||
#define MMC_CID_PNM0(pCid) (uint8_t)SD_CID(pCid, 56, 8) /**< Product name byte 0 */
|
||||
|
||||
#define SD_CID_PRV1(pCid) (uint8_t)SD_CID(pCid, 60, 4) /**< Product revision major number */
|
||||
#define SD_CID_PRV0(pCid) (uint8_t)SD_CID(pCid, 56, 4) /**< Product revision minor number */
|
||||
#define MMC_CID_PRV1(pCid) (uint8_t)SD_CID(pCid, 52, 4) /**< Product revision major number */
|
||||
#define MMC_CID_PRV0(pCid) (uint8_t)SD_CID(pCid, 48, 4) /**< Product revision minor number */
|
||||
|
||||
#define SD_CID_PSN3(pCid) (uint8_t)SD_CID(pCid, 48, 8) /**< Product serial 3 */
|
||||
#define SD_CID_PSN2(pCid) (uint8_t)SD_CID(pCid, 40, 8) /**< Product serial 2 */
|
||||
#define SD_CID_PSN1(pCid) (uint8_t)SD_CID(pCid, 32, 8) /**< Product serial 1 */
|
||||
#define SD_CID_PSN0(pCid) (uint8_t)SD_CID(pCid, 24, 8) /**< Product serial 0 */
|
||||
#define MMC_CID_PSN3(pCid) (uint8_t)SD_CID(pCid, 40, 8) /**< Product serial 3 */
|
||||
#define MMC_CID_PSN2(pCid) (uint8_t)SD_CID(pCid, 32, 8) /**< Product serial 2 */
|
||||
#define MMC_CID_PSN1(pCid) (uint8_t)SD_CID(pCid, 24, 8) /**< Product serial 1 */
|
||||
#define MMC_CID_PSN0(pCid) (uint8_t)SD_CID(pCid, 16, 8) /**< Product serial 0 */
|
||||
|
||||
#define SD_CID_MDT_Y(pCid) (uint8_t)SD_CID(pCid, 12, 8) /**< Manufacturing Year (0=2000) */
|
||||
#define SD_CID_MDT_M(pCid) (uint8_t)SD_CID(pCid, 8, 4) /**< Manufacturing month */
|
||||
#define MMC_CID_MDT_Y(pCid) (uint8_t)SD_CID(pCid, 8, 4) /**< Manufacturing Year (0=1997 or 2013) */
|
||||
#define MMC_CID_MDT_M(pCid) (uint8_t)SD_CID(pCid, 12, 4) /**< Manufacturing month */
|
||||
|
||||
#define SD_CID_CRC(pCid) (uint8_t)SD_CID(pCid, 1, 7) /**< CRC7 checksum */
|
||||
/** @}*/
|
||||
|
||||
/** CSD register access macros (128 bits, 16 * 8 bits, 4 * 32 bits */
|
||||
#define SD_CSD(pCsd, field, bits) SD_BITS32(pCsd, 128, field, bits)
|
||||
#define SD_CSD_STRUCTURE(pCsd) (uint8_t)SD_CSD(pCsd, 126, 2) /**< CSD structure */
|
||||
#define SD_CSD_STRUCTURE_1_0 0 /**< SD v1.01~1.10, v2.0/Std Capacity */
|
||||
#define SD_CSD_STRUCTURE_2_0 1 /**< SD v2.0/HC */
|
||||
#define MMC_CSD_STRUCTURE_1_0 0 /**< MMC v1.0~1.2 */
|
||||
#define MMC_CSD_STRUCTURE_1_1 1 /**< MMC v1.4~2.2 */
|
||||
#define MMC_CSD_STRUCTURE_1_2 2 /**< MMC v3.1~3.31(v4.0), v4.1~(>v4.1) */
|
||||
#define MMC_CSD_SPEC_VERS(pCsd) (uint8_t)SD_CSD(pCsd, 122, 4) /**< System spec version */
|
||||
#define MMC_CSD_SPEC_VERS_1_0 0 /**< MMC v1.0~1.2 */
|
||||
#define MMC_CSD_SPEC_VERS_1_4 1 /**< MMC v1.4 */
|
||||
#define MMC_CSD_SPEC_VERS_2_0 2 /**< MMC v2.0~2.2 */
|
||||
#define MMC_CSD_SPEC_VERS_3_1 3 /**< MMC v3.1~3.31 */
|
||||
#define MMC_CSD_SPEC_VERS_4_0 4 /**< MMC v4.0(v4.0), v4.1~(>v4.1) */
|
||||
#define SD_CSD_TAAC(pCsd) (uint8_t)SD_CSD(pCsd, 112, 8) /**< Data read-access-time-1 */
|
||||
#define SD_CSD_NSAC(pCsd) (uint8_t)SD_CSD(pCsd, 104, 8) /**< Data read access-time-2 in CLK cycles */
|
||||
#define SD_CSD_TRAN_SPEED(pCsd) (uint8_t)SD_CSD(pCsd, 96, 8) /**< Max. data transfer rate */
|
||||
#define SD_CSD_CCC(pCsd) (uint16_t)SD_CSD(pCsd, 84, 12) /**< Card command class */
|
||||
#define SD_CSD_READ_BL_LEN(pCsd) (uint8_t)SD_CSD(pCsd, 80, 4) /**< Max. read data block length */
|
||||
#define SD_CSD_READ_BL_PARTIAL(pCsd) (uint8_t)SD_CSD(pCsd, 79, 1) /**< Bartial blocks for read allowed */
|
||||
#define SD_CSD_WRITE_BLK_MISALIGN(pCsd) (uint8_t)SD_CSD(pCsd, 78, 1) /**< Write block misalignment */
|
||||
#define SD_CSD_READ_BLK_MISALIGN(pCsd) (uint8_t)SD_CSD(pCsd, 77, 1) /**< Read block misalignment */
|
||||
#define SD_CSD_DSR_IMP(pCsd) (uint8_t)SD_CSD(pCsd, 76, 1) /**< DSP implemented */
|
||||
#define SD_CSD_C_SIZE(pCsd) (uint16_t)((SD_CSD(pCsd, 72, 2) << 10) | \
|
||||
(SD_CSD(pCsd, 64, 8) << 2) | \
|
||||
SD_CSD(pCsd, 62, 2)) /**< Device size */
|
||||
#define SD2_CSD_C_SIZE(pCsd) ((SD_CSD(pCsd, 64, 6) << 16) | \
|
||||
(SD_CSD(pCsd, 56, 8) << 8) | \
|
||||
SD_CSD(pCsd, 48, 8)) /**< Device size v2.0 */
|
||||
#define SD_CSD_VDD_R_CURR_MIN(pCsd) (uint8_t)SD_CSD(pCsd, 59, 3) /**< Max. read current VDD min */
|
||||
#define SD_CSD_VDD_R_CURR_MAX(pCsd) (uint8_t)SD_CSD(pCsd, 56, 3) /**< Max. read current VDD max */
|
||||
#define SD_CSD_VDD_W_CURR_MIN(pCsd) (uint8_t)SD_CSD(pCsd, 53, 3) /**< Max. write current VDD min */
|
||||
#define SD_CSD_VDD_W_CURR_MAX(pCsd) (uint8_t)SD_CSD(pCsd, 50, 3) /**< Max. write current VDD max */
|
||||
#define SD_CSD_C_SIZE_MULT(pCsd) (uint8_t)SD_CSD(pCsd, 47, 3) /**< Device size multiplier */
|
||||
#define SD_CSD_ERASE_BLK_EN(pCsd) (uint8_t)SD_CSD(pCsd, 46, 1) /**< Erase single block enable */
|
||||
#define SD_CSD_SECTOR_SIZE(pCsd) (uint8_t)((SD_CSD(pCsd, 40, 6) << 1) | \
|
||||
SD_CSD(pCsd, 39, 1)) /**< Erase sector size*/
|
||||
#define SD_CSD_WP_GRP_SIZE(pCsd) (uint8_t)SD_CSD(pCsd, 32, 7) /**< Write protect group size*/
|
||||
#define MMC_CSD_ERASE_GRP_SIZE(pCsd) (uint8_t)SD_CSD(pCsd, 42, 5) /**< Erase group size */
|
||||
#define MMC_CSD_ERASE_GRP_MULT(pCsd) (uint8_t)SD_CSD(pCsd, 37, 5) /**< Erase group size multiplier */
|
||||
#define MMC_CSD_WP_GRP_SIZE(pCsd) (uint8_t)SD_CSD(pCsd, 32, 5) /**< Write protect group size*/
|
||||
#define SD_CSD_WP_GRP_ENABLE(pCsd) (uint8_t)SD_CSD(pCsd, 31, 1) /**< write protect group enable*/
|
||||
#define MMC_CSD_DEFAULT_ECC(pCsd) (uint8_t)SD_CSD(pCsd, 29, 2) /**< Manufacturer default ECC */
|
||||
#define SD_CSD_R2W_FACTOR(pCsd) (uint8_t)SD_CSD(pCsd, 26, 3) /**< Write speed factor*/
|
||||
#define SD_CSD_WRITE_BL_LEN(pCsd) (uint8_t)((SD_CSD(pCsd, 24, 2) << 2) | \
|
||||
SD_CSD(pCsd, 22, 2)) /**< Max write block length*/
|
||||
#define SD_CSD_WRITE_BL_PARTIAL(pCsd) (uint8_t)SD_CSD(pCsd, 21, 1) /**< Partial blocks for write allowed*/
|
||||
#define SD_CSD_CONTENT_PROT_APP(pCsd) (uint8_t)SD_CSD(pCsd, 16, 1) /**< File format group*/
|
||||
#define SD_CSD_FILE_FORMAT_GRP(pCsd) (uint8_t)SD_CSD(pCsd, 15, 1) /**< File format group*/
|
||||
#define SD_CSD_COPY(pCsd) (uint8_t)SD_CSD(pCsd, 14, 1) /**< Copy flag (OTP)*/
|
||||
#define SD_CSD_PERM_WRITE_PROTECT(pCsd) (uint8_t)SD_CSD(pCsd, 13, 1) /**< Permanent write protect*/
|
||||
#define SD_CSD_TMP_WRITE_PROTECT(pCsd) (uint8_t)SD_CSD(pCsd, 12, 1) /**< Temporary write protection*/
|
||||
#define SD_CSD_FILE_FORMAT(pCsd) (uint8_t)SD_CSD(pCsd, 10, 2) /**< File format*/
|
||||
#define MMC_CSD_ECC(pCsd) (uint8_t)SD_CSD(pCsd, 8, 2) /**< ECC */
|
||||
#define MMC_CSD_ECC_NONE 0 /**< none */
|
||||
#define MMC_CSD_ECC_BCH 1 /**< BCH, 3 correctable bits per block */
|
||||
#define SD_CSD_CRC(pCsd) (uint8_t)SD_CSD(pCsd, 1, 7) /**< CRC*/
|
||||
|
||||
#define SD_CSD_MULT(pCsd) (uint16_t)(1u << (SD_CSD_C_SIZE_MULT(pCsd) + 2))
|
||||
#define SD_CSD_BLOCKNR(pCsd) ((SD_CSD_C_SIZE(pCsd) + 1ul) * SD_CSD_MULT(pCsd))
|
||||
#define SD_CSD_BLOCKNR_HC(pCsd) ((SD2_CSD_C_SIZE(pCsd) + 1ul) * 1024ull)
|
||||
#define SD_CSD_BLOCK_LEN(pCsd) (uint16_t)(1u << SD_CSD_READ_BL_LEN(pCsd))
|
||||
#define SD_CSD_TOTAL_SIZE(pCsd) ((uint64_t)SD_CSD_BLOCKNR(pCsd) * SD_CSD_BLOCK_LEN(pCsd))
|
||||
#define SD_CSD_TOTAL_SIZE_HC(pCsd) ((SD2_CSD_C_SIZE(pCsd) + 1ul) * 512ull * 1024ull)
|
||||
/** @}*/
|
||||
|
||||
|
||||
|
||||
|
||||
#define t_usleep(d,t) sdmmc_device_sleep(d,t,2)
|
||||
#define t_msleep(d,t) sdmmc_device_sleep(d,t,1)
|
||||
#define t_xsleep(d,t) sdmmc_device_sleep(d,t,0)
|
||||
|
||||
extern uint8_t sdmmc_device_lowlevelcfg(SdmmcDriver *driver);
|
||||
extern bool sdmmc_device_initialize(SdmmcDriver *driver);
|
||||
extern void sdmmc_device_deInit(SdmmcDriver *drv);
|
||||
extern void sdmmc_device_poll(SdmmcDriver *driver);
|
||||
extern uint32_t sdmmc_device_command(SdmmcDriver *driver);
|
||||
extern uint32_t sdmmc_device_control(SdmmcDriver *driver, uint32_t bCtl);
|
||||
extern void sdmmc_device_sleep(SdmmcDriver *driver,uint32_t t,uint32_t m);
|
||||
extern void sdmmc_device_startTimeCount(SdmmcDriver *driver);
|
||||
extern void sdmmc_device_checkTimeCount(SdmmcDriver *driver);
|
||||
|
||||
extern uint8_t sdmmc_device_start(SdmmcDriver *drv);
|
||||
extern uint8_t sdmmc_device_identify(SdmmcDriver *drv);
|
||||
|
||||
extern uint8_t sdmmc_get_bus_width(SdmmcDriver *driver);
|
||||
extern uint8_t HwSetHsMode(SdmmcDriver *drv, uint8_t timingMode);
|
||||
extern uint32_t HwSetBusWidth( SdmmcDriver *drv,uint8_t newWidth);
|
||||
extern uint8_t HwSetClock(SdmmcDriver *drv, uint32_t * pIoValClk);
|
||||
extern uint8_t HwPowerDevice(SdmmcDriver *drv, uint8_t nowSwitchOn);
|
||||
extern bool HwIsTimingSupported(SdmmcDriver *drv, uint8_t timingMode);
|
||||
extern uint32_t SdmmcGetMaxFreq(SdmmcDriver *drv);
|
||||
extern uint8_t SdMmcSelect(SdmmcDriver *drv, uint16_t address, uint8_t statCheck);
|
||||
extern uint8_t SdMmcIdentify(SdmmcDriver *drv);
|
||||
extern uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry);
|
||||
extern void SdMmcUpdateInformation(SdmmcDriver *drv, bool csd, bool extData);
|
||||
extern bool sdmmc_is_busy(SdmmcDriver *driver);
|
||||
|
||||
#endif /* CH_SDMMC_DEVICE_H_ */
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef CH_SDMMC_MACROS_H_
|
||||
#define CH_SDMMC_MACROS_H_
|
||||
|
||||
|
||||
#if !defined(CACHE_ALIGNED)
|
||||
#define CACHE_ALIGNED __attribute__((aligned(L1_CACHE_BYTES)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @brief NO CACHE attribute
|
||||
*/
|
||||
#if !defined(NO_CACHE)
|
||||
#define NO_CACHE __attribute__((section (".nocache")))
|
||||
#endif
|
||||
|
||||
#define IS_CACHE_ALIGNED(x) ((((uint32_t)(x)) & (L1_CACHE_BYTES - 1)) == 0)
|
||||
#if !defined(ROUND_INT_DIV)
|
||||
#define ROUND_INT_DIV(n,d) (((n) + ((d)-1)) / (d))
|
||||
#endif
|
||||
#define ROUND_UP_MULT(x,m) (((x) + ((m)-1)) & ~((m)-1))
|
||||
#define CEIL_INT_DIV(n,d) (((n) + (d) - 1) / (d))
|
||||
#define ABS_DIFF(a,b) ((a) < (b) ? (b) - (a) : (a) - (b))
|
||||
#define ARRAY_SIZE(x) (sizeof ((x)) / sizeof(*(x)))
|
||||
|
||||
#define _PrintTitle(s) TRACE(s)
|
||||
#define _PrintField(f,v) TRACE_1(f,v)
|
||||
|
||||
static inline uint32_t max_u32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t min_u32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
#endif /* CH_SDMMC_MACROS_H_ */
|
|
@ -1,377 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "hal.h"
|
||||
|
||||
#if (SAMA_USE_SDMMC == TRUE)
|
||||
|
||||
#include "sama_sdmmc_lld.h"
|
||||
#include "ch_sdmmc_device.h"
|
||||
#include "ch_sdmmc_cmds.h"
|
||||
#include "ch_sdmmc_sd.h"
|
||||
|
||||
#ifndef SDMMC_TRIM_MMC
|
||||
|
||||
/** Check if MMC Spec version 4 */
|
||||
#define MMC_IsVer4(pSd) ( MMC_CSD_SPEC_VERS(pSd->CSD) >= 4 )
|
||||
|
||||
/** Check if MMC CSD structure is 1.2 (3.1 or later) */
|
||||
#define MMC_IsCSDVer1_2(pSd) \
|
||||
( (SD_CSD_STRUCTURE(pSd->CSD)==2) \
|
||||
||(SD_CSD_STRUCTURE(pSd->CSD)>2&&MMC_EXT_CSD_STRUCTURE(pSd->EXT)>=2) )
|
||||
|
||||
|
||||
/** MMC transfer multiplier factor codes (1/10) list */
|
||||
|
||||
const uint8_t mmcTransMultipliers[16] = {
|
||||
0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
|
||||
};
|
||||
|
||||
|
||||
static uint8_t mmcSelectBuswidth(SdmmcDriver *driver, uint8_t busWidth, bool ddr)
|
||||
{
|
||||
uint8_t error;
|
||||
uint32_t status;
|
||||
MmcCmd6Arg cmd6Arg = {
|
||||
.access = 0x3, /* Write byte in the EXT_CSD register */
|
||||
.index = MMC_EXT_BUS_WIDTH_I, /* Target byte in EXT_CSD */
|
||||
.value = MMC_EXT_BUS_WIDTH_1BIT, /* Byte value */
|
||||
};
|
||||
|
||||
if (busWidth == 8)
|
||||
cmd6Arg.value = MMC_EXT_BUS_WIDTH_8BITS
|
||||
| (ddr ? MMC_EXT_BUS_WIDTH_DDR : 0);
|
||||
else if (busWidth == 4)
|
||||
cmd6Arg.value = MMC_EXT_BUS_WIDTH_4BITS
|
||||
| (ddr ? MMC_EXT_BUS_WIDTH_DDR : 0);
|
||||
else if (busWidth != 1)
|
||||
return SDMMC_PARAM;
|
||||
|
||||
error = MmcCmd6(driver, &cmd6Arg, &status);
|
||||
|
||||
if (error)
|
||||
return SDMMC_ERR;
|
||||
else if (status & STATUS_MMC_SWITCH)
|
||||
return SDMMC_NOT_SUPPORTED;
|
||||
|
||||
return SDMMC_OK;
|
||||
}
|
||||
|
||||
static uint8_t mmcDetectBuswidth(SdmmcDriver *driver)
|
||||
{
|
||||
uint8_t error, busWidth, mask = 0xff, i, len;
|
||||
sSdCard *pSd =&driver->card;
|
||||
//assert(sizeof(pSd->sandbox1) >= 8);
|
||||
//assert(sizeof(pSd->sandbox2) >= 8);
|
||||
|
||||
memset(pSd->sandbox1, 0, 8);
|
||||
for (busWidth = 8; busWidth != 0; busWidth /= busWidth == 8 ? 2 : 4) {
|
||||
error = HwSetBusWidth(driver, busWidth);
|
||||
if (error)
|
||||
continue;
|
||||
switch (busWidth) {
|
||||
case 8:
|
||||
pSd->sandbox1[0] = 0x55;
|
||||
pSd->sandbox1[1] = 0xaa;
|
||||
break;
|
||||
case 4:
|
||||
pSd->sandbox1[0] = 0x5a;
|
||||
pSd->sandbox1[1] = 0;
|
||||
break;
|
||||
case 1:
|
||||
pSd->sandbox1[0] = 0x80;
|
||||
pSd->sandbox1[1] = 0;
|
||||
break;
|
||||
}
|
||||
len = (uint8_t)max_u32(busWidth, 2);
|
||||
error = Cmd19(driver, pSd->sandbox1, len, NULL);
|
||||
|
||||
if (error) {
|
||||
/* Devices which do not respond to CMD19 - which results
|
||||
* in the driver returning SDMMC_ERROR_NORESPONSE -
|
||||
* simply do not support the bus test procedure.
|
||||
* When the device responds to CMD19, mind the
|
||||
* difference with other data write commands: further
|
||||
* to host data, the device does not emit the CRC status
|
||||
* token. Typically the peripheral reports the anomaly,
|
||||
* and the driver is likely to return SDMMC_ERR_IO. */
|
||||
if (error != SDMMC_ERR_IO)
|
||||
return 0;
|
||||
}
|
||||
error = Cmd14(driver, pSd->sandbox2, busWidth, NULL);
|
||||
|
||||
if (error)
|
||||
continue;
|
||||
if (busWidth == 1) {
|
||||
mask = 0xc0;
|
||||
pSd->sandbox2[0] &= mask;
|
||||
}
|
||||
len = busWidth == 8 ? 2 : 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((pSd->sandbox1[i] ^ pSd->sandbox2[i]) != mask)
|
||||
break;
|
||||
}
|
||||
if (i == len)
|
||||
break;
|
||||
}
|
||||
return busWidth;
|
||||
}
|
||||
|
||||
|
||||
uint8_t MmcGetExtInformation(SdmmcDriver *driver)
|
||||
{
|
||||
sSdCard *pSd = &driver->card;
|
||||
/* MMC 4.0 Higher version */
|
||||
if (SD_CSD_STRUCTURE(pSd->CSD) >= 2 && MMC_IsVer4(pSd))
|
||||
return MmcCmd8(driver);
|
||||
else
|
||||
return SDMMC_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
uint8_t MmcInit(SdmmcDriver *driver)
|
||||
{
|
||||
MmcCmd6Arg sw_arg = {
|
||||
.access = 0x3, /* Write byte in the EXT_CSD register */
|
||||
};
|
||||
uint64_t mem_size;
|
||||
uint32_t freq, drv_err, status;
|
||||
uint8_t error, tim_mode, pwr_class, width;
|
||||
bool flag;
|
||||
|
||||
tim_mode = driver->card.bSpeedMode = SDMMC_TIM_MMC_BC;
|
||||
/* The host then issues the command ALL_SEND_CID (CMD2) to the card to get
|
||||
* its unique card identification (CID) number.
|
||||
* Card that is unidentified (i.e. which is in Ready State) sends its CID
|
||||
* number as the response (on the CMD line). */
|
||||
error = Cmd2(driver);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Thereafter, the host issues SET_RELATIVE_ADDR (CMD3) to assign the
|
||||
* device a dedicated relative card address (RCA), which is shorter than
|
||||
* CID and which is used to address the card in the future data transfer
|
||||
* mode. Once the RCA is received the card state changes to the Stand-by
|
||||
* State. */
|
||||
error = Cmd3(driver);
|
||||
if (error)
|
||||
return error;
|
||||
//else
|
||||
TRACE_DEBUG_1("RCA=%u\n\r", driver->card.wAddress);
|
||||
|
||||
/* SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
|
||||
* e.g. block length, card storage capacity, etc... */
|
||||
error = Cmd9(driver);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Calculate transfer speed */
|
||||
freq = SdmmcGetMaxFreq(driver);
|
||||
|
||||
error = HwSetClock(driver, &freq);
|
||||
|
||||
if (error != SDMMC_OK && error != SDMMC_CHANGED)
|
||||
return error;
|
||||
|
||||
driver->card.dwCurrSpeed = freq;
|
||||
|
||||
/* Now select the card, to TRAN state */
|
||||
error = SdMmcSelect(driver, driver->card.wAddress, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* If CSD:SPEC_VERS indicates v4.0 or higher, read EXT_CSD */
|
||||
error = MmcGetExtInformation(driver);
|
||||
/* Consider HS200 timing mode */
|
||||
if (error == SDMMC_OK && MMC_EXT_EXT_CSD_REV(driver->card.EXT) >= 6
|
||||
&& MMC_IsCSDVer1_2((&driver->card)) && MMC_EXT_CARD_TYPE(driver->card.EXT) & 0x10
|
||||
&& HwIsTimingSupported(driver, SDMMC_TIM_MMC_HS200))
|
||||
tim_mode = SDMMC_TIM_MMC_HS200;
|
||||
/* Consider High Speed DDR timing mode */
|
||||
else if (error == SDMMC_OK && MMC_EXT_EXT_CSD_REV(driver->card.EXT) >= 4
|
||||
&& MMC_IsCSDVer1_2((&driver->card)) && MMC_EXT_CARD_TYPE(driver->card.EXT) & 0x4
|
||||
&& HwIsTimingSupported(driver, SDMMC_TIM_MMC_HS_DDR))
|
||||
tim_mode = SDMMC_TIM_MMC_HS_DDR;
|
||||
/* Consider High Speed SDR timing mode */
|
||||
else if (error == SDMMC_OK
|
||||
&& MMC_IsCSDVer1_2((&driver->card)) && MMC_EXT_CARD_TYPE(driver->card.EXT) & 0x1
|
||||
&& HwIsTimingSupported(driver, SDMMC_TIM_MMC_HS_SDR))
|
||||
tim_mode = SDMMC_TIM_MMC_HS_SDR;
|
||||
/* Check power requirements of the device */
|
||||
if (error == SDMMC_OK) {
|
||||
if (tim_mode == SDMMC_TIM_MMC_HS200)
|
||||
pwr_class = MMC_EXT_PWR_CL_200_195(driver->card.EXT);
|
||||
else if (tim_mode == SDMMC_TIM_MMC_HS_DDR)
|
||||
pwr_class = MMC_EXT_PWR_CL_DDR_52_360(driver->card.EXT);
|
||||
else if (tim_mode == SDMMC_TIM_MMC_HS_SDR)
|
||||
pwr_class = MMC_EXT_PWR_CL_52_360(driver->card.EXT);
|
||||
else
|
||||
pwr_class = MMC_EXT_PWR_CL_26_360(driver->card.EXT);
|
||||
|
||||
if (pwr_class != 0) {
|
||||
sw_arg.index = MMC_EXT_POWER_CLASS_I;
|
||||
sw_arg.value = 0xf;
|
||||
error = MmcCmd6(driver, &sw_arg, &status);
|
||||
if (error) {
|
||||
TRACE_DEBUG_1("Pwr class %s\n\r",SD_StringifyRetCode(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable High Speed SDR timing mode */
|
||||
if (tim_mode == SDMMC_TIM_MMC_HS_SDR || tim_mode == SDMMC_TIM_MMC_HS_DDR) {
|
||||
|
||||
sw_arg.index = MMC_EXT_HS_TIMING_I;
|
||||
sw_arg.value = MMC_EXT_HS_TIMING_EN;
|
||||
|
||||
error = MmcCmd6(driver, &sw_arg, &status);
|
||||
|
||||
if (error == SDMMC_OK)
|
||||
error = HwSetHsMode(driver, SDMMC_TIM_MMC_HS_SDR);
|
||||
if (error == SDMMC_OK)
|
||||
error = Cmd13(driver, &status);
|
||||
if (error == SDMMC_OK && (status & ~STATUS_STATE
|
||||
& ~STATUS_READY_FOR_DATA
|
||||
|| (status & STATUS_STATE) != STATUS_TRAN))
|
||||
error = SDMMC_STATE;
|
||||
if (error == SDMMC_OK) {
|
||||
driver->card.bSpeedMode = SDMMC_TIM_MMC_HS_SDR;
|
||||
freq = SdmmcGetMaxFreq(driver);
|
||||
error = HwSetClock(driver, &freq);
|
||||
driver->card.dwCurrSpeed = freq;
|
||||
error = error == SDMMC_CHANGED ? SDMMC_OK : error;
|
||||
}
|
||||
if (error != SDMMC_OK) {
|
||||
TRACE_ERROR_1("HS %s\n\r", SD_StringifyRetCode(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consider using the widest supported data bus */
|
||||
if (MMC_IsCSDVer1_2((&driver->card)) && MMC_IsVer4((&driver->card))) {
|
||||
|
||||
width = mmcDetectBuswidth(driver);
|
||||
|
||||
if (width > 1) {
|
||||
|
||||
error = mmcSelectBuswidth(driver, width,tim_mode == SDMMC_TIM_MMC_HS_DDR);
|
||||
|
||||
if (error == SDMMC_OK)
|
||||
error = HwSetBusWidth(driver, width);
|
||||
|
||||
if (error == SDMMC_OK)
|
||||
driver->card.bBusMode = width;
|
||||
|
||||
if (error == SDMMC_OK && tim_mode == SDMMC_TIM_MMC_HS_DDR)
|
||||
/* Switch to High Speed DDR timing mode */
|
||||
error = HwSetHsMode(driver, tim_mode);
|
||||
if (error == SDMMC_OK)
|
||||
error = Cmd13(driver, &status);
|
||||
if (error == SDMMC_OK && (status & ~STATUS_STATE
|
||||
& ~STATUS_READY_FOR_DATA
|
||||
|| (status & STATUS_STATE) != STATUS_TRAN))
|
||||
error = SDMMC_STATE;
|
||||
if (error == SDMMC_OK
|
||||
&& tim_mode == SDMMC_TIM_MMC_HS_DDR)
|
||||
driver->card.bSpeedMode = tim_mode;
|
||||
else if (error) {
|
||||
TRACE_ERROR_1("Width/DDR %s\n\r",SD_StringifyRetCode(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable HS200 timing mode */
|
||||
if (tim_mode == SDMMC_TIM_MMC_HS200 && driver->card.bBusMode > 1) {
|
||||
sw_arg.index = MMC_EXT_HS_TIMING_I;
|
||||
/* Select device output Driver Type-0, i.e. 50 ohm nominal
|
||||
* output impedance.
|
||||
* TODO select the optimal device output Driver Type.
|
||||
* That depends on board design. Use an oscilloscope to observe
|
||||
* signal integrity, and among the driver types that meet rise
|
||||
* and fall time requirements, select the weakest. */
|
||||
sw_arg.value = MMC_EXT_HS_TIMING_HS200 | MMC_EXT_HS_TIMING_50R;
|
||||
error = MmcCmd6(driver, &sw_arg, &status);
|
||||
if (error == SDMMC_OK)
|
||||
error = HwSetHsMode(driver, tim_mode);
|
||||
if (error == SDMMC_OK) {
|
||||
error = Cmd13(driver, &status);
|
||||
if (error == SDMMC_OK && (status & ~STATUS_STATE
|
||||
& ~STATUS_READY_FOR_DATA
|
||||
|| (status & STATUS_STATE) != STATUS_TRAN))
|
||||
error = SDMMC_STATE;
|
||||
}
|
||||
if (error == SDMMC_OK) {
|
||||
driver->card.bSpeedMode = tim_mode;
|
||||
freq = SdmmcGetMaxFreq(driver);
|
||||
error = HwSetClock(driver, &freq);
|
||||
driver->card.dwCurrSpeed = freq;
|
||||
error = error == SDMMC_CHANGED ? SDMMC_OK : error;
|
||||
}
|
||||
if (error != SDMMC_OK) {
|
||||
TRACE_ERROR_1("HS200 %s\n\r", SD_StringifyRetCode(error));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update card information since status changed */
|
||||
flag = driver->card.bSpeedMode >= SDMMC_TIM_MMC_HS_SDR;
|
||||
if (flag || driver->card.bBusMode > 1)
|
||||
SdMmcUpdateInformation(driver, flag, true);
|
||||
|
||||
/* MMC devices have the SET_BLOCK_COUNT command part of both the
|
||||
* block-oriented read and the block-oriented write commands,
|
||||
* i.e. class 2 and class 4 commands.
|
||||
* FIXME we should normally check CSD.CCC before issuing any MMC block-
|
||||
* oriented read/write command. */
|
||||
driver->card.bSetBlkCnt = 1;
|
||||
/* Ask the driver to implicitly send the SET_BLOCK_COUNT command,
|
||||
* immediately before every READ_MULTIPLE_BLOCK and WRITE_MULTIPLE_BLOCK
|
||||
* command. */
|
||||
driver->control_param = driver->card.bSetBlkCnt;
|
||||
drv_err = sdmmc_device_control(driver,SDMMC_IOCTL_SET_LENPREFIX);
|
||||
|
||||
/* In case the driver does not support this function, we'll take it in
|
||||
* charge. */
|
||||
if (driver->card.bSetBlkCnt && drv_err == SDMMC_OK && driver->control_param)
|
||||
driver->card.bSetBlkCnt = 0;
|
||||
|
||||
driver->card.wCurrBlockLen = SDMMC_BLOCK_SIZE;
|
||||
|
||||
if (MMC_IsCSDVer1_2((&driver->card)) && MMC_IsVer4((&driver->card))) {
|
||||
/* Get size from EXT_CSD */
|
||||
if (MMC_EXT_DATA_SECTOR_SIZE(driver->card.EXT)
|
||||
== MMC_EXT_DATA_SECT_4KIB)
|
||||
driver->card.wBlockSize = 4096;
|
||||
else
|
||||
driver->card.wBlockSize = 512;
|
||||
driver->card.dwNbBlocks = MMC_EXT_SEC_COUNT(driver->card.EXT)
|
||||
/ (driver->card.wBlockSize / 512UL);
|
||||
/* Device density >= 4 GiB does not fit 32-bit dwTotalSize */
|
||||
driver->card.dwTotalSize = MMC_EXT_SEC_COUNT(driver->card.EXT);
|
||||
if (driver->card.dwTotalSize >= 0x800000)
|
||||
driver->card.dwTotalSize = 0xFFFFFFFF;
|
||||
else
|
||||
driver->card.dwTotalSize *= 512UL;
|
||||
}
|
||||
else {
|
||||
driver->card.wBlockSize = 512;
|
||||
mem_size = SD_CSD_TOTAL_SIZE(driver->card.CSD);
|
||||
driver->card.dwNbBlocks = (uint32_t)(mem_size >> 9);
|
||||
driver->card.dwTotalSize = mem_size >> 32 ? 0xFFFFFFFF
|
||||
: (uint32_t)mem_size;
|
||||
}
|
||||
|
||||
/* Check device status and eat past exceptions, which would otherwise
|
||||
* prevent upcoming data transaction routines from reliably checking
|
||||
* fresh exceptions. */
|
||||
error = Cmd13(driver, &status);
|
||||
if (error)
|
||||
return error;
|
||||
status = status & ~STATUS_STATE & ~STATUS_READY_FOR_DATA & ~STATUS_APP_CMD;
|
||||
if (status) {
|
||||
TRACE_WARNING_1("st %lx\n\r", status);
|
||||
}
|
||||
|
||||
return SDMMC_OK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef CH_SDMMC_MMC_H_
|
||||
#define CH_SDMMC_MMC_H_
|
||||
|
||||
extern uint8_t MmcInit(SdmmcDriver *driver);
|
||||
extern uint8_t MmcGetExtInformation(SdmmcDriver *driver);
|
||||
|
||||
|
||||
#endif /* CH_SDMMC_MMC_H_ */
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef CH_SDMMC_SAMA5D2_H_
|
||||
#define CH_SDMMC_SAMA5D2_H_
|
||||
|
||||
|
||||
#define EXT_SIZE 512
|
||||
#define SSR_SIZE 64
|
||||
#define SCR_SIZE 8
|
||||
#define SB1_SIZE 64
|
||||
#define SB2_SIZE 8
|
||||
|
||||
#define SDMMC_BUFFER_SIZE (EXT_SIZE + SSR_SIZE + SCR_SIZE + SB1_SIZE + SB2_SIZE)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDMMC_SLOT0 = 0,
|
||||
SDMMC_SLOT1
|
||||
}sdmmcslots_t;
|
||||
|
||||
/* mask for board capabilities defines: voltage, slot type and 8-bit support */
|
||||
#define CAPS0_MASK (SDMMC_CA0R_V33VSUP | SDMMC_CA0R_V30VSUP | \
|
||||
SDMMC_CA0R_V18VSUP | SDMMC_CA0R_SLTYPE_Msk | \
|
||||
SDMMC_CA0R_ED8SUP)
|
||||
/* SOM1 */
|
||||
#if defined(BOARD_ATSAM5D27_SOM1)
|
||||
#define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_V18VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_REMOVABLECARD | \
|
||||
SDMMC_CA0R_ED8SUP)
|
||||
|
||||
#define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_REMOVABLECARD)
|
||||
#elif defined(BOARD_ATSAM5D2_XULT)
|
||||
#define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_V18VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_EMBEDDED | \
|
||||
SDMMC_CA0R_ED8SUP)
|
||||
|
||||
#define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_REMOVABLECARD)
|
||||
#else
|
||||
#define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_V18VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_EMBEDDED | \
|
||||
SDMMC_CA0R_ED8SUP)
|
||||
|
||||
#define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \
|
||||
SDMMC_CA0R_SLTYPE_REMOVABLECARD)
|
||||
#endif
|
||||
|
||||
#endif /* CH_SDMMC_SAMA5D2_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,117 +0,0 @@
|
|||
#ifndef CH_SDMMC_SD_H_
|
||||
#define CH_SDMMC_SD_H_
|
||||
|
||||
|
||||
/** \addtogroup sd_scr_acc SD SCR register fields
|
||||
* @{
|
||||
*/
|
||||
/** SCR (Configuration register) access macros (64 bits, 2 * 32 bits, 8 * 8 bits). */
|
||||
#define SD_SCR(pScr, field, bits) SD_GetField(pScr, 64, field, bits)
|
||||
#define SD_SCR_STRUCTURE(pScr) (uint8_t)SD_SCR(pScr, 60, 4)
|
||||
#define SD_SCR_STRUCTURE_1_0 0 /**< SD v1.01~3.01 */
|
||||
#define SD_SCR_SD_SPEC(pScr) (uint8_t)SD_SCR(pScr, 56, 4)
|
||||
#define SD_SCR_SD_SPEC_1_0 0 /**< SD v1.0~1.01 */
|
||||
#define SD_SCR_SD_SPEC_1_10 1 /**< SD v1.10 */
|
||||
#define SD_SCR_SD_SPEC_2_00 2 /**< SD v2.00 */
|
||||
#define SD_SCR_DATA_STAT_AFTER_ERASE(pScr) (uint8_t)SD_SCR(pScr, 55, 1)
|
||||
#define SD_SCR_SD_SECURITY(pScr) (uint8_t)SD_SCR(pScr, 52, 3)
|
||||
#define SD_SCR_SD_SECURITY_NO 0 /**< No security */
|
||||
#define SD_SCR_SD_SECURITY_NOTUSED 1 /**< Not used */
|
||||
#define SD_SCR_SD_SECURITY_1_01 2 /**< Version 1.01 */
|
||||
#define SD_SCR_SD_SECURITY_2_00 3 /**< Version 2.00 */
|
||||
#define SD_SCR_SD_BUS_WIDTHS(pScr) (uint8_t)SD_SCR(pScr, 48, 4)
|
||||
#define SD_SCR_SD_BUS_WIDTH_1BITS (1 << 0) /**< 1 bit (DAT0) */
|
||||
#define SD_SCR_SD_BUS_WIDTH_4BITS (1 << 2) /**< 4 bit (DAT0~3) */
|
||||
#define SD_SCR_SD_SPEC3(pScr) (uint8_t)SD_SCR(pScr, 47, 1)
|
||||
#define SD_SCR_SD_SPEC_3_0 1 /**< SD v3.0X */
|
||||
#define SD_SCR_EX_SECURITY(pScr) (uint8_t)SD_SCR(pScr, 43, 4)
|
||||
#define SD_SCR_EX_SECURITY_NO 0 /**< No extended security */
|
||||
#define SD_SCR_SD_SPEC4(pScr) (uint8_t)SD_SCR(pScr, 42, 1)
|
||||
#define SD_SCR_SD_SPEC_4_X 1 /**< SD v4.XX */
|
||||
#define SD_SCR_CMD58_SUPPORT(pScr) (uint8_t)SD_SCR(pScr, 35, 1)
|
||||
#define SD_SCR_CMD48_SUPPORT(pScr) (uint8_t)SD_SCR(pScr, 34, 1)
|
||||
#define SD_SCR_CMD23_SUPPORT(pScr) (uint8_t)SD_SCR(pScr, 33, 1)
|
||||
#define SD_SCR_CMD20_SUPPORT(pScr) (uint8_t)SD_SCR(pScr, 32, 1)
|
||||
/** \addtogroup sd_switch_status SD Switch Status fields
|
||||
* @{
|
||||
*/
|
||||
/** SD Switch Status access macros (512 bits, 16 * 32 bits, 64 * 8 bits). */
|
||||
#define SD_SWITCH_ST(p, field, bits) SD_GetField(p, 512, field, bits)
|
||||
#define SD_SWITCH_ST_MAX_CURR_CONSUMPTION(p) (uint16_t)SD_SWITCH_ST(p, 496, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP6_INFO(p) (uint16_t)SD_SWITCH_ST(p, 480, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP5_INFO(p) (uint16_t)SD_SWITCH_ST(p, 464, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP4_INFO(p) (uint16_t)SD_SWITCH_ST(p, 448, 16)
|
||||
#define SD_SWITCH_ST_MAX_PWR_0_72W 0x0
|
||||
#define SD_SWITCH_ST_MAX_PWR_1_44W 0x1
|
||||
#define SD_SWITCH_ST_MAX_PWR_2_16W 0x2
|
||||
#define SD_SWITCH_ST_MAX_PWR_2_88W 0x3
|
||||
#define SD_SWITCH_ST_MAX_PWR_1_80W 0x4
|
||||
#define SD_SWITCH_ST_FUN_GRP3_INFO(p) (uint16_t)SD_SWITCH_ST(p, 432, 16)
|
||||
#define SD_SWITCH_ST_OUT_DRV_B 0x0
|
||||
#define SD_SWITCH_ST_OUT_DRV_A 0x1
|
||||
#define SD_SWITCH_ST_OUT_DRV_C 0x2
|
||||
#define SD_SWITCH_ST_OUT_DRV_D 0x3
|
||||
#define SD_SWITCH_ST_FUN_GRP2_INFO(p) (uint16_t)SD_SWITCH_ST(p, 416, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP1_INFO(p) (uint16_t)SD_SWITCH_ST(p, 400, 16)
|
||||
#define SD_SWITCH_ST_ACC_DS 0x0
|
||||
#define SD_SWITCH_ST_ACC_HS 0x1
|
||||
#define SD_SWITCH_ST_ACC_SDR50 0x2
|
||||
#define SD_SWITCH_ST_ACC_SDR104 0x3
|
||||
#define SD_SWITCH_ST_ACC_DDR50 0x4
|
||||
#define SD_SWITCH_ST_FUN_GRP6_RC(p) (uint8_t) SD_SWITCH_ST(p, 396, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP5_RC(p) (uint8_t) SD_SWITCH_ST(p, 392, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP4_RC(p) (uint8_t) SD_SWITCH_ST(p, 388, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP3_RC(p) (uint8_t) SD_SWITCH_ST(p, 384, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP2_RC(p) (uint8_t) SD_SWITCH_ST(p, 380, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP1_RC(p) (uint8_t) SD_SWITCH_ST(p, 376, 4)
|
||||
#define SD_SWITCH_ST_FUN_GRP_RC_ERROR 0xF
|
||||
#define SD_SWITCH_ST_DATA_STRUCT_VER(p) (uint8_t) SD_SWITCH_ST(p, 368, 8)
|
||||
#define SD_SWITCH_ST_FUN_GRP6_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 352, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP5_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 336, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP4_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 320, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP3_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 304, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP2_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 288, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP1_BUSY(p) (uint16_t)SD_SWITCH_ST(p, 272, 16)
|
||||
#define SD_SWITCH_ST_FUN_GRP_FUN_BUSY(funNdx) (1 << (funNdx))
|
||||
/** @}*/
|
||||
|
||||
/** We support 2.7 ~ 3.3V cards */
|
||||
#define SD_HOST_VOLTAGE_RANGE (SD_OCR_VDD_27_28 +\
|
||||
SD_OCR_VDD_28_29 +\
|
||||
SD_OCR_VDD_29_30 +\
|
||||
SD_OCR_VDD_30_31 +\
|
||||
SD_OCR_VDD_31_32 +\
|
||||
SD_OCR_VDD_32_33 +\
|
||||
SD_OCR_VDD_33_34 +\
|
||||
SD_OCR_VDD_34_35 +\
|
||||
SD_OCR_VDD_35_36 )
|
||||
|
||||
|
||||
|
||||
/** @}*/
|
||||
|
||||
extern uint8_t SD_GetStatus(SdmmcDriver *driver);
|
||||
extern uint8_t SdDecideBuswidth(SdmmcDriver *drv);
|
||||
extern uint8_t SdEnableHighSpeed(SdmmcDriver *drv);
|
||||
extern uint32_t SD_GetField(const uint8_t *reg, uint16_t reg_len, uint16_t field_start,
|
||||
uint8_t field_len);
|
||||
extern void SdGetExtInformation(SdmmcDriver *drv);
|
||||
|
||||
extern void SD_DumpStatus(const sSdCard *pSd);
|
||||
extern void SD_DumpCID(const sSdCard *pSd);
|
||||
extern void SD_DumpSCR(const uint8_t *pSCR);
|
||||
extern void SD_DumpCSD(const sSdCard *pSd);
|
||||
extern void SD_DumpExtCSD(const uint8_t *pExtCSD);
|
||||
extern void SD_DumpSSR(const uint8_t *pSSR);
|
||||
|
||||
extern const char * SD_StringifyRetCode(uint32_t dwRCode);
|
||||
extern const char * SD_StringifyIOCtrl(uint32_t dwCtrl);
|
||||
|
||||
extern uint8_t SD_Read(SdmmcDriver *driver,uint32_t address,void *pData, uint32_t length);
|
||||
extern uint8_t SD_Write(SdmmcDriver *driver,uint32_t address,const void *pData,uint32_t length);
|
||||
extern uint8_t SD_ReadBlocks(SdmmcDriver *driver, uint32_t address, void *pData, uint32_t nbBlocks);
|
||||
extern uint8_t SD_WriteBlocks(SdmmcDriver *driver, uint32_t address, const void *pData, uint32_t nbBlocks);
|
||||
extern uint8_t SD_ReadBlocks(SdmmcDriver *driver, uint32_t address, void *pData, uint32_t nbBlocks);
|
||||
extern uint8_t SD_GetWpStatus(SdmmcDriver *driver);
|
||||
|
||||
#endif /* CH_SDMMC_SD_H_ */
|
|
@ -1,293 +0,0 @@
|
|||
#include "hal.h"
|
||||
|
||||
#if (SAMA_USE_SDMMC == TRUE)
|
||||
|
||||
#include "sama_sdmmc_lld.h"
|
||||
#include "ch_sdmmc_device.h"
|
||||
#include "ch_sdmmc_sdio.h"
|
||||
#include "ch_sdmmc_cmds.h"
|
||||
#include "ch_sdmmc_sd.h"
|
||||
|
||||
#ifndef SDMMC_TRIM_SDIO
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint8_t SdioInit(SdmmcDriver *driver)
|
||||
{
|
||||
uint32_t freq;
|
||||
uint8_t error;
|
||||
|
||||
driver->card.bSpeedMode = SDMMC_TIM_SD_DS;
|
||||
|
||||
HwSetHsMode(driver, driver->card.bSpeedMode);
|
||||
/* Thereafter, the host issues CMD3 (SEND_RELATIVE_ADDR) asks the
|
||||
* card to publish a new relative card address (RCA), which is shorter than
|
||||
* CID and which is used to address the card in the future data transfer
|
||||
* mode. Once the RCA is received the card state changes to the Stand-by
|
||||
* State. At this point, if the host wants to assign another RCA number, it
|
||||
* can ask the card to publish a new number by sending another CMD3 command
|
||||
* to the card. The last published RCA is the actual RCA number of the
|
||||
* card. */
|
||||
error = Cmd3(driver);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
TRACE_1("RCA=%u\n\r", driver->card.wAddress);
|
||||
|
||||
/* Now select the card, to TRAN state */
|
||||
error = SdMmcSelect(driver,driver->card.wAddress, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Enable more bus width Mode */
|
||||
error = SdDecideBuswidth(driver);
|
||||
if (error) {
|
||||
TRACE_1("Bus width %s\n\r", SD_StringifyRetCode(error));
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
|
||||
/* Consider High-Speed timing mode */
|
||||
error = SdEnableHighSpeed(driver);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Increase device clock frequency */
|
||||
freq = SdioGetMaxFreq(driver);
|
||||
|
||||
error = HwSetClock(driver, &freq);
|
||||
driver->card.dwCurrSpeed = freq;
|
||||
if (error != SDMMC_OK && error != SDMMC_CHANGED) {
|
||||
TRACE_1("clk %s\n\r", SD_StringifyRetCode(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
return SDMMC_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read one or more bytes from SDIO card, using RW_DIRECT command.
|
||||
* \param pSd Pointer to SdCard instance.
|
||||
* \param functionNum Function number.
|
||||
* \param address First register address to read from.
|
||||
* \param pData Pointer to data buffer.
|
||||
* \param size Buffer size, number of bytes to read.
|
||||
* \return 0 if successful; otherwise returns an \ref sdmmc_rc "error code".
|
||||
*/
|
||||
uint8_t SDIO_ReadDirect(SdmmcDriver *sdmmcp,
|
||||
uint8_t functionNum,
|
||||
uint32_t address, uint8_t * pData, uint32_t size)
|
||||
{
|
||||
uint8_t error;
|
||||
uint32_t status;
|
||||
|
||||
sSdCard *pSd = &sdmmcp->card;
|
||||
|
||||
if (pSd->bCardType & CARD_TYPE_bmSDIO) {
|
||||
if (size == 0)
|
||||
return SDMMC_PARAM;
|
||||
while (size--) {
|
||||
status = 0;
|
||||
error =
|
||||
Cmd52(sdmmcp, 0, functionNum, 0, address++, &status);
|
||||
if (pData)
|
||||
*pData++ = (uint8_t) status;
|
||||
if (error || status & STATUS_SDIO_R5) {
|
||||
//trace_error("IOrdRegs %luB@%lu %s st %lx\n\r",
|
||||
// size, address, SD_StringifyRetCode(error),
|
||||
// status);
|
||||
return SDMMC_ERR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return SDMMC_NOT_SUPPORTED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find SDIO ManfID, Fun0 tuple.
|
||||
* \param pSd Pointer to \ref sSdCard instance.
|
||||
* \param address Search area start address.
|
||||
* \param size Search area size.
|
||||
* \param pAddrManfID Pointer to ManfID address value buffer.
|
||||
* \param pAddrFunc0 Pointer to Func0 address value buffer.
|
||||
*/
|
||||
uint8_t SdioFindTuples(SdmmcDriver *sdmmcp,
|
||||
uint32_t address, uint32_t size,
|
||||
uint32_t * pAddrManfID, uint32_t * pAddrFunc0)
|
||||
{
|
||||
uint8_t error, tmp[3];
|
||||
uint32_t addr = address;
|
||||
uint8_t flagFound = 0; /* 1:Manf, 2:Func0 */
|
||||
uint32_t addManfID = 0, addFunc0 = 0;
|
||||
for (; flagFound != 3;) {
|
||||
error = SDIO_ReadDirect(sdmmcp, SDIO_CIA, addr, tmp, 3);
|
||||
if (error)
|
||||
return error;
|
||||
/* End */
|
||||
if (tmp[0] == CISTPL_END)
|
||||
break;
|
||||
/* ManfID */
|
||||
else if (tmp[0] == CISTPL_MANFID) {
|
||||
flagFound |= 1;
|
||||
addManfID = addr;
|
||||
}
|
||||
/* Func0 */
|
||||
else if (tmp[0] == CISTPL_FUNCE && tmp[2] == 0x00) {
|
||||
flagFound |= 2;
|
||||
addFunc0 = addr;
|
||||
}
|
||||
/* Tuple error ? */
|
||||
if (tmp[1] == 0)
|
||||
break;
|
||||
/* Next address */
|
||||
addr += (tmp[1] + 2);
|
||||
if (addr > (address + size))
|
||||
break;
|
||||
}
|
||||
if (pAddrManfID)
|
||||
*pAddrManfID = addManfID;
|
||||
if (pAddrFunc0)
|
||||
*pAddrFunc0 = addFunc0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SdioGetMaxFreq(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
uint8_t error;
|
||||
uint32_t addr = 0, rate;
|
||||
uint8_t buf[6];
|
||||
|
||||
/* Check Func0 tuple in CIS area */
|
||||
error = SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_CIS_PTR_REG,(uint8_t *)&addr, 3);
|
||||
|
||||
if (error)
|
||||
return 0;
|
||||
|
||||
error = SdioFindTuples(sdmmcp, addr, 256, NULL, &addr);
|
||||
|
||||
if (error || !addr)
|
||||
return 0;
|
||||
|
||||
/* Fun0 tuple: fn0_blk_siz & max_tran_speed */
|
||||
error = SDIO_ReadDirect(sdmmcp, SDIO_CIA, addr, buf, 6);
|
||||
|
||||
if (error)
|
||||
return 0;
|
||||
|
||||
rate = SdmmcDecodeTransSpeed(buf[5], sdmmcTransUnits,
|
||||
sdTransMultipliers);
|
||||
|
||||
if (sdmmcp->card.bSpeedMode == SDMMC_TIM_SD_SDR104 && rate == 200000ul)
|
||||
rate = 208000ul;
|
||||
else if (sdmmcp->card.bSpeedMode == SDMMC_TIM_SD_DDR50)
|
||||
rate /= 2ul;
|
||||
else if (sdmmcp->card.bSpeedMode == SDMMC_TIM_SD_HS && rate == 25000ul)
|
||||
rate *= 2ul;
|
||||
|
||||
return rate * 1000ul;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display SDIO card informations (CIS, tuple ...)
|
||||
* \param pSd Pointer to \ref sSdCard instance.
|
||||
*/
|
||||
void SDIO_DumpCardInformation(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
uint32_t tmp = 0, addrCIS = 0, addrManfID = 0, addrFuncE = 0;
|
||||
uint8_t *p = (uint8_t *) & tmp;
|
||||
uint8_t buf[16];
|
||||
|
||||
/* CCCR */
|
||||
_PrintTitle("CCCR");
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_CCCR_REG, p, 1);
|
||||
_PrintField("SDIO 0x%02lX", (tmp & SDIO_SDIO) >> 4);
|
||||
_PrintField("CCCR 0x%02lX", (tmp & SDIO_CCCR) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_SD_REV_REG, p, 1);
|
||||
_PrintField("SD 0x%02lX", (tmp & SDIO_SD) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_IOE_REG, p, 1);
|
||||
_PrintField("IOE 0x%02lX", (tmp & SDIO_IOE) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_IOR_REG, p, 1);
|
||||
_PrintField("IOR 0x%02lX", (tmp & SDIO_IOR) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_IEN_REG, p, 1);
|
||||
_PrintField("IEN 0x%02lX", (tmp & SDIO_IEN) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_INT_REG, p, 1);
|
||||
_PrintField("INT %lu", (tmp & SDIO_INT) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_BUS_CTRL_REG, p, 1);
|
||||
_PrintField("CD 0x%lX", (tmp & SDIO_CD) >> 7);
|
||||
_PrintField("SCSI 0x%lX", (tmp & SDIO_SCSI) >> 6);
|
||||
_PrintField("ECSI 0x%lX", (tmp & SDIO_ECSI) >> 5);
|
||||
_PrintField("BUS_WIDTH 0x%lX", (tmp & SDIO_BUSWIDTH) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_CAP_REG, p, 1);
|
||||
_PrintField("4BLS 0x%lX", (tmp & SDIO_4BLS) >> 7);
|
||||
_PrintField("LSC 0x%lX", (tmp & SDIO_LSC) >> 6);
|
||||
_PrintField("E4MI 0x%lX", (tmp & SDIO_E4MI) >> 5);
|
||||
_PrintField("S4MI 0x%lX", (tmp & SDIO_S4MI) >> 4);
|
||||
_PrintField("SBS 0x%lX", (tmp & SDIO_SBS) >> 3);
|
||||
_PrintField("SRW 0x%lX", (tmp & SDIO_SRW) >> 2);
|
||||
_PrintField("SMB 0x%lX", (tmp & SDIO_SMB) >> 1);
|
||||
_PrintField("SDC 0x%lX", (tmp & SDIO_SDC) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_CIS_PTR_REG, p, 3);
|
||||
_PrintField("CIS_PTR 0x%06lX", tmp);
|
||||
addrCIS = tmp;
|
||||
tmp = 0;
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_BUS_SUSP_REG, p, 1);
|
||||
_PrintField("BR 0x%lX", (tmp & SDIO_BR) >> 1);
|
||||
_PrintField("BS 0x%lX", (tmp & SDIO_BS) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_FUN_SEL_REG, p, 1);
|
||||
_PrintField("DF 0x%lX", (tmp & SDIO_DF) >> 7);
|
||||
_PrintField("FS 0x%lX", (tmp & SDIO_FS) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_EXEC_REG, p, 1);
|
||||
_PrintField("EX 0x%lX", (tmp & SDIO_EX) >> 0);
|
||||
_PrintField("EXM 0x%lX", (tmp & SDIO_EXM) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_READY_REG, p, 1);
|
||||
_PrintField("RF 0x%lX", (tmp & SDIO_RF) >> 1);
|
||||
_PrintField("RFM 0x%lX", (tmp & SDIO_RFM) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_FN0_BLKSIZ_REG, p, 2);
|
||||
_PrintField("FN0_SIZE %lu", tmp);
|
||||
tmp = 0;
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_POWER_REG, p, 1);
|
||||
_PrintField("EMPC 0x%lX", (tmp & SDIO_EMPC) >> 1);
|
||||
_PrintField("SMPC 0x%lX", (tmp & SDIO_SMPC) >> 0);
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_HS_REG, p, 1);
|
||||
_PrintField("EHS 0x%lX", (tmp & SDIO_EHS) >> 1);
|
||||
_PrintField("SHS 0x%lX", (tmp & SDIO_SHS) >> 0);
|
||||
/* Metaformat */
|
||||
SdioFindTuples(sdmmcp, addrCIS, 128, &addrManfID, &addrFuncE);
|
||||
if (addrManfID != 0) {
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, addrManfID, buf, 6);
|
||||
_PrintTitle("CISTPL_MANFID");
|
||||
_PrintField("MANF 0x%04X", (uint16_t)buf[3] << 8 | buf[2]);
|
||||
_PrintField("CARD 0x%04X", (uint16_t)buf[5] << 8 | buf[4]);
|
||||
}
|
||||
if (addrFuncE != 0) {
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, addrFuncE, buf, 6);
|
||||
_PrintTitle("CISTPL_FUNCE Fun0");
|
||||
_PrintField("BL_SIZE %u", (uint16_t)buf[4] << 8 | buf[3]);
|
||||
_PrintField("MAX_TRAN_SPD 0x%02X", buf[5]);
|
||||
}
|
||||
/* I/O function 1 */
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, SDIO_FBR_ADDR(1, SDIO_FBR_CIS_PTR),
|
||||
p, 3);
|
||||
addrFuncE = 0;
|
||||
/* TODO Augment SdioFindTuples so it finds CISTPL_FUNCE for Function 1
|
||||
* with Extended Data 01h */
|
||||
SdioFindTuples(sdmmcp, tmp, 256, NULL, &addrFuncE);
|
||||
if (addrFuncE != 0) {
|
||||
SDIO_ReadDirect(sdmmcp, SDIO_CIA, addrFuncE, buf, 16);
|
||||
_PrintTitle("CISTPL_FUNCE Fun1");
|
||||
_PrintField("MAX_BLK_SIZE %u", (uint16_t)buf[0xf] << 8
|
||||
| buf[0xe]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,295 +0,0 @@
|
|||
#ifndef CH_SDMMC_SDIO_H_
|
||||
#define CH_SDMMC_SDIO_H_
|
||||
|
||||
|
||||
|
||||
/** \addtogroup sdio_api
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Constants
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/** \addtogroup sdio_status SDIO Status bits
|
||||
* @{
|
||||
*/
|
||||
#define SDIO_R1_IDLE (1ul << 0) /**< in idle state */
|
||||
#define SDIO_R1_ILLEGAL_COMMAND (1ul << 2) /**< illegal command */
|
||||
#define SDIO_R1_COM_CRC_ERROR (1ul << 3) /**< COM CRC error */
|
||||
#define SDIO_R1_FUNCN_ERROR (1ul << 4) /**< Function number error */
|
||||
#define SDIO_R1_PARAM_ERROR (1ul << 6) /**< Parameter error */
|
||||
|
||||
#define SDIO_R6_COM_CRC_ERROR (1ul << 15) /**< CRC check of command fails */
|
||||
#define SDIO_R6_ILLEGAL_COMMAND (1ul << 14) /**< Command not legal for the state */
|
||||
#define SDIO_R6_ERROR (1ul << 13) /**< General or unknown error */
|
||||
|
||||
#define SDIO_R5_Pos (8) /**< R5 starting position */
|
||||
#define SDIO_R5_COM_CRC_ERROR (1ul << 15)
|
||||
#define SDIO_R5_ILLEGAL_COMMAND (1ul << 14)
|
||||
#define SDIO_R5_IO_STATE (3ul << 12) /**< DIS/CMD/TRN/RFU */
|
||||
#define SDIO_R5_STATE_DIS (0ul << 12)
|
||||
#define SDIO_R5_STATE_CMD (1ul << 12)
|
||||
#define SDIO_R5_STATE_TRN (2ul << 12)
|
||||
#define SDIO_R5_STATE_RFU (3ul << 12)
|
||||
#define SDIO_R5_ERROR (1ul << 11)
|
||||
#define SDIO_R5_FUNCN_ERROR (1ul << 9)
|
||||
#define SDIO_R5_OUT_OF_RANGE (1ul << 8)
|
||||
|
||||
#define SDIO_R4_OCR (0xF << 0) /**< OCR */
|
||||
#define SDIO_R4_MP (1ul << 27) /**< Memory Present */
|
||||
#define SDIO_R4_NF (3ul << 28) /**< Number of Functions */
|
||||
/** @}*/
|
||||
|
||||
/** \addtogroup sdio_fun_def SDIO Functions
|
||||
* Here lists SDIO functions definitions
|
||||
* - \ref SDIO_CIA or \ref SDIO_FN0
|
||||
* - \ref SDIO_FN1
|
||||
* - \ref SDIO_FN2
|
||||
* - \ref SDIO_FN3
|
||||
* - \ref SDIO_FN4
|
||||
* - \ref SDIO_FN5
|
||||
* - \ref SDIO_FN6
|
||||
* - \ref SDIO_FN7
|
||||
* @{*/
|
||||
#define SDIO_CIA 0 /**< SDIO Function 0 (CIA) */
|
||||
#define SDIO_FN0 0 /**< SDIO Function 0 */
|
||||
#define SDIO_FN1 1 /**< SDIO Function 1 */
|
||||
#define SDIO_FN2 2 /**< SDIO Function 2 */
|
||||
#define SDIO_FN3 3 /**< SDIO Function 3 */
|
||||
#define SDIO_FN4 4 /**< SDIO Function 4 */
|
||||
#define SDIO_FN5 5 /**< SDIO Function 5 */
|
||||
#define SDIO_FN6 6 /**< SDIO Function 6 */
|
||||
#define SDIO_FN7 7 /**< SDIO Function 7 */
|
||||
/** @}*/
|
||||
|
||||
/** \addtogroup sdio_cccr_def SDIO Card Common Control Registers (CCCR)
|
||||
* Here lists SDIO CCCR definitions
|
||||
* -# \ref SDIO_CCCR_REG
|
||||
* -# \ref SDIO_SD_REV_REG
|
||||
* -# \ref SDIO_IOE_REG
|
||||
* -# \ref SDIO_IOR_REG
|
||||
* -# \ref SDIO_IEN_REG
|
||||
* -# \ref SDIO_INT_REG
|
||||
* -# \ref SDIO_IOA_REG
|
||||
* -# \ref SDIO_BUS_CTRL_REG
|
||||
* -# \ref SDIO_CAP_REG
|
||||
* -# \ref SDIO_CIS_PTR_REG
|
||||
* -# .
|
||||
* -# .
|
||||
* -# \ref SDIO_BUS_SUSP_REG
|
||||
* -# \ref SDIO_FUN_SEL_REG
|
||||
* -# \ref SDIO_EXEC_REG
|
||||
* -# \ref SDIO_READY_REG
|
||||
* -# \ref SDIO_FN0_BLKSIZ_REG
|
||||
* -# .
|
||||
* -# \ref SDIO_POWER_REG
|
||||
* -# \ref SDIO_HS_REG
|
||||
* @{*/
|
||||
#define SDIO_CCCR_REG 0x00 /**< CCCR/SDIO revision (RO) */
|
||||
#define SDIO_CCCR (0xFUL << 0)/**< CCCR Format Version number */
|
||||
#define SDIO_CCCR_1_00 (0x0UL << 0)/**< CCCR/FBR Version 1.00 */
|
||||
#define SDIO_CCCR_1_10 (0x1UL << 0)/**< CCCR/FBR Version 1.10 */
|
||||
#define SDIO_CCCR_1_20 (0x2UL << 0)/**< CCCR/FBR Version 1.20 */
|
||||
#define SDIO_SDIO (0xFUL << 4)/**< SDIO Specification */
|
||||
#define SDIO_SDIO_1_00 (0x0UL << 4)/**< SDIO Specification 1.00 */
|
||||
#define SDIO_SDIO_1_10 (0x1UL << 4)/**< SDIO Specification 1.10 */
|
||||
#define SDIO_SDIO_1_20 (0x2UL << 4)/**< SDIO Specification 1.20(unreleased) */
|
||||
#define SDIO_SDIO_2_00 (0x3UL << 4)/**< SDIO Specification Version 2.00 */
|
||||
#define SDIO_SD_REV_REG 0x01 /**< SD Specification Revision (RO) */
|
||||
#define SDIO_SD (0xFUL << 0)/**< SD Physical Specification */
|
||||
#define SDIO_SD_1_01 (0x0UL << 0)/**< SD 1.01 (Mar 2000) */
|
||||
#define SDIO_SD_1_10 (0x1UL << 0)/**< SD 1.10 (Oct 2004) */
|
||||
#define SDIO_SD_2_00 (0x2UL << 0)/**< SD 2.00 (May 2006) */
|
||||
#define SDIO_IOE_REG 0x02 /**< I/O Enable (R/W) */
|
||||
#define SDIO_IOE 0xFEUL /**< Enable/Disable Function */
|
||||
#define SDIO_IOE_FN1 (0x1UL << 1)/**< Function 1 Enable/Disable */
|
||||
#define SDIO_IOE_FN2 (0x1UL << 2)/**< Function 2 Enable/Disable */
|
||||
#define SDIO_IOE_FN3 (0x1UL << 3)/**< Function 3 Enable/Disable */
|
||||
#define SDIO_IOE_FN4 (0x1UL << 4)/**< Function 4 Enable/Disable */
|
||||
#define SDIO_IOE_FN5 (0x1UL << 5)/**< Function 5 Enable/Disable */
|
||||
#define SDIO_IOE_FN6 (0x1UL << 6)/**< Function 6 Enable/Disable */
|
||||
#define SDIO_IOE_FN7 (0x1UL << 7)/**< Function 7 Enable/Disable */
|
||||
#define SDIO_IOR_REG 0x03 /**< I/O Ready (RO) */
|
||||
#define SDIO_IOR 0xFEUL /**< I/O Function Ready */
|
||||
#define SDIO_IOR_FN1 (0x1UL << 1)/**< Function 1 ready */
|
||||
#define SDIO_IOR_FN2 (0x1UL << 2)/**< Function 2 ready */
|
||||
#define SDIO_IOR_FN3 (0x1UL << 3)/**< Function 3 ready */
|
||||
#define SDIO_IOR_FN4 (0x1UL << 4)/**< Function 4 ready */
|
||||
#define SDIO_IOR_FN5 (0x1UL << 5)/**< Function 5 ready */
|
||||
#define SDIO_IOR_FN6 (0x1UL << 6)/**< Function 6 ready */
|
||||
#define SDIO_IOR_FN7 (0x1UL << 7)/**< Function 7 ready */
|
||||
#define SDIO_IEN_REG 0x04 /**< Int Enable */
|
||||
#define SDIO_IENM 0x01UL /**< Int Enable Master (R/W) */
|
||||
#define SDIO_IEN 0xFEUL /**< Int Enable for function (R/W) */
|
||||
#define SDIO_IEN_FN1 (0x1UL << 1)/**< Function 1 Int Enable */
|
||||
#define SDIO_IEN_FN2 (0x1UL << 2)/**< Function 2 Int Enable */
|
||||
#define SDIO_IEN_FN3 (0x1UL << 3)/**< Function 3 Int Enable */
|
||||
#define SDIO_IEN_FN4 (0x1UL << 4)/**< Function 4 Int Enable */
|
||||
#define SDIO_IEN_FN5 (0x1UL << 5)/**< Function 5 Int Enable */
|
||||
#define SDIO_IEN_FN6 (0x1UL << 6)/**< Function 6 Int Enable */
|
||||
#define SDIO_IEN_FN7 (0x1UL << 7)/**< Function 7 Int Enable */
|
||||
#define SDIO_INT_REG 0x05 /**< Int Pending */
|
||||
#define SDIO_INT 0xFE /**< Int Pending for functions (RO) */
|
||||
#define SDIO_INT_FN1 (0x1UL << 1)/**< Function 1 Int pending */
|
||||
#define SDIO_INT_FN2 (0x1UL << 2)/**< Function 2 Int pending */
|
||||
#define SDIO_INT_FN3 (0x1UL << 3)/**< Function 3 Int pending */
|
||||
#define SDIO_INT_FN4 (0x1UL << 4)/**< Function 4 Int pending */
|
||||
#define SDIO_INT_FN5 (0x1UL << 5)/**< Function 5 Int pending */
|
||||
#define SDIO_INT_FN6 (0x1UL << 6)/**< Function 6 Int pending */
|
||||
#define SDIO_INT_FN7 (0x1UL << 7)/**< Function 7 Int pending */
|
||||
#define SDIO_IOA_REG 0x06 /**< I/O Abort */
|
||||
#define SDIO_AS (0x7UL << 0)/**< Abort Select In Order (WO) */
|
||||
#define SDIO_AS_FN1 (0x1UL << 0)/**< Abort function 1 IO */
|
||||
#define SDIO_AS_FN2 (0x2UL << 0)/**< Abort function 2 IO */
|
||||
#define SDIO_AS_FN3 (0x3UL << 0)/**< Abort function 3 IO */
|
||||
#define SDIO_AS_FN4 (0x4UL << 0)/**< Abort function 4 IO */
|
||||
#define SDIO_AS_FN5 (0x5UL << 0)/**< Abort function 5 IO */
|
||||
#define SDIO_AS_FN6 (0x6UL << 0)/**< Abort function 6 IO */
|
||||
#define SDIO_AS_FN7 (0x7UL << 0)/**< Abort function 7 IO */
|
||||
#define SDIO_RES (0x1UL << 3)/**< IO CARD RESET (WO) */
|
||||
#define SDIO_BUS_CTRL_REG 0x07 /**< Bus Interface Control */
|
||||
#define SDIO_BUSWIDTH (0x3UL << 0)/**< Data bus width (R/W) */
|
||||
#define SDIO_BUSWIDTH_1B (0x0UL << 0)/**< 1-bit data bus */
|
||||
#define SDIO_BUSWIDTH_4B (0x2UL << 0)/**< 4-bit data bus */
|
||||
#define SDIO_ECSI (0x1UL << 5)/**< Enable Continuous SPI interrupt (R/W) */
|
||||
#define SDIO_SCSI (0x1UL << 6)/**< Support Continuous SPI interrupt (RO) */
|
||||
#define SDIO_CD (0x1UL << 7)/**< Connect(0)/Disconnect(1) pull-up on CD/DAT[3] (R/W) */
|
||||
#define SDIO_CAP_REG 0x08 /**< Card Capability */
|
||||
#define SDIO_SDC (0x1UL << 0)/**< Support Direct Commands during data transfer (RO) */
|
||||
#define SDIO_SMB (0x1UL << 1)/**< Support Multi-Block (RO) */
|
||||
#define SDIO_SRW (0x1UL << 2)/**< Support Read Wait (RO) */
|
||||
#define SDIO_SBS (0x1UL << 3)/**< Support Suspend/Resume (RO) */
|
||||
#define SDIO_S4MI (0x1UL << 4)/**< Support interrupt between blocks of data in 4-bit SD mode (RO) */
|
||||
#define SDIO_E4MI (0x1UL << 5)/**< Enable interrupt between blocks of data in 4-bit SD mode (R/W) */
|
||||
#define SDIO_LSC (0x1UL << 6)/**< Low-Speed Card (RO) */
|
||||
#define SDIO_4BLS (0x1UL << 7)/**< 4-bit support for Low-Speed Card (RO) */
|
||||
#define SDIO_CIS_PTR_REG 0x09 /**< Pointer to CIS (3B, LSB first) */
|
||||
#define SDIO_BUS_SUSP_REG 0x0C /**< Bus Suspend */
|
||||
#define SDIO_BS (0x1UL << 0)/**< Bus Status (transfer on DAT[x] lines) (RO) */
|
||||
#define SDIO_BR (0x1UL << 1)/**< Bus Release Request/Status (R/W) */
|
||||
#define SDIO_FUN_SEL_REG 0x0D /**< Function select */
|
||||
#define SDIO_DF (0x1UL << 7)/**< Resume Data Flag (RO) */
|
||||
#define SDIO_FS (0xFUL << 0)/**< Select Function (R/W) */
|
||||
#define SDIO_FS_CIA (0x0UL << 0)/**< Select CIA (function 0) */
|
||||
#define SDIO_FS_FN1 (0x1UL << 0)/**< Select Function 1 */
|
||||
#define SDIO_FS_FN2 (0x2UL << 0)/**< Select Function 2 */
|
||||
#define SDIO_FS_FN3 (0x3UL << 0)/**< Select Function 3 */
|
||||
#define SDIO_FS_FN4 (0x4UL << 0)/**< Select Function 4 */
|
||||
#define SDIO_FS_FN5 (0x5UL << 0)/**< Select Function 5 */
|
||||
#define SDIO_FS_FN6 (0x6UL << 0)/**< Select Function 6 */
|
||||
#define SDIO_FS_FN7 (0x7UL << 0)/**< Select Function 7 */
|
||||
#define SDIO_FS_MEM (0x8UL << 0)/**< Select memory in combo card */
|
||||
#define SDIO_EXEC_REG 0x0E /**< Exec Flags (RO) */
|
||||
#define SDIO_EXM (0x1UL << 0)/**< Executing status of memory */
|
||||
#define SDIO_EX (0xFEUL) /**< Executing status of functions */
|
||||
#define SDIO_EX_FN1 (0x1UL << 1)/**< Executing status of function 1 */
|
||||
#define SDIO_EX_FN2 (0x1UL << 2)/**< Executing status of function 2 */
|
||||
#define SDIO_EX_FN3 (0x1UL << 3)/**< Executing status of function 3 */
|
||||
#define SDIO_EX_FN4 (0x1UL << 4)/**< Executing status of function 4 */
|
||||
#define SDIO_EX_FN5 (0x1UL << 5)/**< Executing status of function 5 */
|
||||
#define SDIO_EX_FN6 (0x1UL << 6)/**< Executing status of function 6 */
|
||||
#define SDIO_EX_FN7 (0x1UL << 7)/**< Executing status of function 7 */
|
||||
#define SDIO_READY_REG 0x0F /**< Ready Flags (RO) */
|
||||
#define SDIO_RFM (0x1UL << 0)/**< Ready Flag for memory */
|
||||
#define SDIO_RF (0xFEUL) /**< Ready Flag for functions */
|
||||
#define SDIO_RF_FN1 (0x1UL << 1)/**< Ready Flag for function 1 */
|
||||
#define SDIO_RF_FN2 (0x1UL << 2)/**< Ready Flag for function 2 */
|
||||
#define SDIO_RF_FN3 (0x1UL << 3)/**< Ready Flag for function 3 */
|
||||
#define SDIO_RF_FN4 (0x1UL << 4)/**< Ready Flag for function 4 */
|
||||
#define SDIO_RF_FN5 (0x1UL << 5)/**< Ready Flag for function 5 */
|
||||
#define SDIO_RF_FN6 (0x1UL << 6)/**< Ready Flag for function 6 */
|
||||
#define SDIO_RF_FN7 (0x1UL << 7)/**< Ready Flag for function 7 */
|
||||
#define SDIO_FN0_BLKSIZ_REG 0x10 /**< FN0 Block Size (2B, LSB first) (R/W) */
|
||||
#define SDIO_POWER_REG 0x12 /**< Power Control */
|
||||
#define SDIO_SMPC (0x1UL << 0)/**< Support Master Power Control (RO) */
|
||||
#define SDIO_EMPC (0x1UL << 1)/**< Enable Master Power Control (R/W) */
|
||||
#define SDIO_HS_REG 0x13 /**< High-Speed */
|
||||
#define SDIO_SHS (0x1UL << 0)/**< Support High-Speed (RO) */
|
||||
#define SDIO_EHS (0x1UL << 1)/**< Enable High-Speed (R/W) */
|
||||
/** @}*/
|
||||
|
||||
/** \addtogroup sdio_fbr_def SDIO Function Basic Registers (FBR)
|
||||
* Here lists SDIO Function Basic Register definitions.
|
||||
* - SDIO_FBR_ADDR()
|
||||
* -# \ref SDIO_FBR_CSA_IF
|
||||
* -# \ref SDIO_FBR_EXT_IF
|
||||
* -# \ref SDIO_FBR_PWR
|
||||
* -# \ref SDIO_FBR_CIS_PTR
|
||||
* -# .
|
||||
* -# .
|
||||
* -# \ref SDIO_FBR_CSA_PTR
|
||||
* -# .
|
||||
* -# .
|
||||
* -# \ref SDIO_FBR_CSA_DATA
|
||||
* -# \ref SDIO_FBR_BLK_SIZ
|
||||
* -# .
|
||||
* @{*/
|
||||
#define SDIO_FBR_ADDR(fn, x) (0x100*(fn) + (x))
|
||||
#define SDIO_FBR_CSA_IF 0x0 /**< CSA and function interface code (RO) */
|
||||
#define SDIO_IFC (0xFUL << 0)/**< Standard SDIO Fun Interface Code */
|
||||
#define SDIO_IFC_NO_IF (0x0UL << 0)/**< No SDIO standard interface */
|
||||
#define SDIO_IFC_UART (0x1UL << 0)/**< UART */
|
||||
#define SDIO_IFC_TA_BT (0x2UL << 0)/**< Type-A Bluetooth */
|
||||
#define SDIO_IFC_TB_BT (0x3UL << 0)/**< Type-B Bluetooth */
|
||||
#define SDIO_IFC_GPS (0x4UL << 0)/**< GPS */
|
||||
#define SDIO_IFC_CAMERA (0x5UL << 0)/**< Camera */
|
||||
#define SDIO_IFC_PHS (0x6UL << 0)/**< PHS */
|
||||
#define SDIO_IFC_WLAN (0x7UL << 0)/**< WLAN */
|
||||
#define SDIO_IFC_ATA (0x8UL << 0)/**< Embedded SDIO-ATA */
|
||||
#define SDIO_IFC_EXT (0xFUL << 0)/**< Check EXT interface code */
|
||||
#define SDIO_SCSA (0x1UL << 6)/**< Function supports Code Storage Area (CSA) */
|
||||
#define SDIO_FBR_CSA (0x1UL << 7)/**< Function CSA enable */
|
||||
#define SDIO_FBR_EXT_IF 0x1 /**< Extended function interface code (RO) */
|
||||
#define SDIO_FBR_PWR 0x2 /**< function power control */
|
||||
#define SDIO_SPS (0x1UL << 0)/**< function support power selection (RO) */
|
||||
#define SDIO_EPS (0x1UL << 1)/**< Low Current Mode/High Current Mode (R/W) */
|
||||
#define SDIO_FBR_CIS_PTR 0x9 /**< Address pointer to function CIS (3B, LSB first) (RO) */
|
||||
#define SDIO_FBR_CSA_PTR 0xC /**< Address pointer to CSA (3B, LSB first) (R/W) */
|
||||
#define SDIO_FBR_CSA_DATA 0xF /**< Read/Write fifo to CSA (R/W) */
|
||||
#define SDIO_FBR_BLK_SIZ 0x10 /**< Block size (2B, LSB first) (R/W) */
|
||||
/** @}*/
|
||||
|
||||
/** \addtogroup sdio_meta_def SDIO Card Metaformat
|
||||
* Here lists definitions for SDIO metaformats.
|
||||
* - \ref CISTPL_NULL
|
||||
* - \ref CISTPL_DEVICE
|
||||
* - \ref CISTPL_CHECKSUM
|
||||
* - \ref CISTPL_VERS_1
|
||||
* - \ref CISTPL_ALTSTR
|
||||
* - \ref CISTPL_MANFID
|
||||
* - \ref CISTPL_FUNCID
|
||||
* - \ref CISTPL_FUNCE
|
||||
* - \ref CISTPL_SDIO_STD
|
||||
* - \ref CISTPL_SDIO_EXT
|
||||
* - \ref CISTPL_END
|
||||
* @{*/
|
||||
#define CISTPL_NULL 0x00 /**< Null tuple (PCMCIA 3.1.9) */
|
||||
#define CISTPL_DEVICE 0x01 /**< Device tuple (PCMCIA 3.2.2) */
|
||||
#define CISTPL_CHECKSUM 0x10 /**< Checksum control (PCMCIA 3.1.1) */
|
||||
#define CISTPL_VERS_1 0x15 /**< Level 1 version (PCMCIA 3.2.10) */
|
||||
#define CISTPL_ALTSTR 0x16 /**< Alternate Language String (PCMCIA 3.2.1) */
|
||||
#define CISTPL_MANFID 0x20 /**< Manufacturer Identification String (PCMCIA 3.2.9) */
|
||||
#define CISTPL_FUNCID 0x21 /**< Function Identification (PCMCIA 3.2.7) */
|
||||
#define CISTPL_FUNCE 0x22 /**< Function Extensions (PCMCIA 3.2.6) */
|
||||
#define CISTPL_SDIO_STD 0x91 /**< Additional information for SDIO (PCMCIA 6.1.2) */
|
||||
#define CISTPL_SDIO_EXT 0x92 /**< Reserved for future SDIO (PCMCIA 6.1.3) */
|
||||
#define CISTPL_END 0xFF /**< The End-of-chain Tuple (PCMCIA 3.1.2) */
|
||||
/** @}*/
|
||||
|
||||
/** Status bits mask for SDIO R5 */
|
||||
#define STATUS_SDIO_R5 (0/*SDIO_R5_STATE*/ \
|
||||
| SDIO_R5_ERROR \
|
||||
| SDIO_R5_FUNCN_ERROR \
|
||||
| SDIO_R5_OUT_OF_RANGE)
|
||||
|
||||
extern uint8_t SdioInit(SdmmcDriver *driver);
|
||||
extern uint8_t SDIO_ReadDirect(SdmmcDriver *sdmmcp,
|
||||
uint8_t functionNum,
|
||||
uint32_t address, uint8_t * pData, uint32_t size);
|
||||
extern uint32_t SdioGetMaxFreq(SdmmcDriver *sdmmcp);
|
||||
|
||||
extern void SDIO_DumpCardInformation(SdmmcDriver *sdmmcp);
|
||||
extern void SDIO_DumpCardInformation(SdmmcDriver *sdmmcp);
|
||||
|
||||
#endif /* CH_SDMMC_SDIO_H_ */
|
|
@ -1,104 +0,0 @@
|
|||
#ifndef CH_SDMMC_TRACE_H_
|
||||
#define CH_SDMMC_TRACE_H_
|
||||
|
||||
|
||||
#if SAMA_SDMMC_TRACE == 1
|
||||
|
||||
#include "chprintf.h"
|
||||
extern BaseSequentialStream * ts;
|
||||
|
||||
#define TRACE(s) chprintf(ts,s)
|
||||
#define TRACE_1(s,v1) chprintf(ts,s,v1)
|
||||
#define TRACE_2(s,v1,v2) chprintf(ts,s,v1,v2)
|
||||
#define TRACE_3(s,v1,v2,v3) chprintf(ts,s,v1,v3)
|
||||
#define TRACE_4(s,v1,v2,v3,v4) chprintf(ts,s,v1,v2,v3,v4)
|
||||
#define TRACE_5(s,v1,v2,v3,v4,v5) chprintf(ts,s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_6(s,v1,v2,v3,v4,v5,v6) chprintf(ts,s,v1,v2,v3,v4,v5,v6)
|
||||
#define TRACE_LEV_1(s,v1) TRACE_1(s,v1);
|
||||
#else
|
||||
#define TRACE(s)
|
||||
#define TRACE_1(s,v1)
|
||||
#define TRACE_2(s,v1,v2)
|
||||
#define TRACE_3(s,v1,v2,v3)
|
||||
#define TRACE_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#endif
|
||||
|
||||
#if SAMA_SDMMC_TRACE_LEVEL >= 1
|
||||
#define TRACE_INFO(s) TRACE(s)
|
||||
#define TRACE_INFO_1(s,v1) TRACE_1(s,v1)
|
||||
#define TRACE_INFO_2(s,v1,v2) TRACE_2(s,v1,v2)
|
||||
#define TRACE_INFO_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
|
||||
#define TRACE_INFO_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_INFO_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_INFO_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#else
|
||||
#define TRACE_INFO(s)
|
||||
#define TRACE_INFO_1(s,v1)
|
||||
#define TRACE_INFO_2(s,v1,v2)
|
||||
#define TRACE_INFO_3(s,v1,v2,v3)
|
||||
#define TRACE_INFO_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_INFO_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_INFO_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#endif
|
||||
|
||||
|
||||
#if SAMA_SDMMC_TRACE_LEVEL >= 2
|
||||
#define TRACE_WARNING(s) TRACE(s)
|
||||
#define TRACE_WARNING_1(s,v1) TRACE_1(s,v1)
|
||||
#define TRACE_WARNING_2(s,v1,v2) TRACE_2(s,v1,v2)
|
||||
#define TRACE_WARNING_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
|
||||
#define TRACE_WARNING_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_WARNING_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_WARNING_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#else
|
||||
#define TRACE_WARNING(s)
|
||||
#define TRACE_WARNING_1(s,v1)
|
||||
#define TRACE_WARNING_2(s,v1,v2)
|
||||
#define TRACE_WARNING_3(s,v1,v2,v3)
|
||||
#define TRACE_WARNING_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_WARNING_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_WARNING_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#endif
|
||||
|
||||
|
||||
#if SAMA_SDMMC_TRACE_LEVEL >= 3
|
||||
#define TRACE_ERROR(s) TRACE(s)
|
||||
#define TRACE_ERROR_1(s,v1) TRACE_1(s,v1)
|
||||
#define TRACE_ERROR_2(s,v1,v2) TRACE_2(s,v1,v2)
|
||||
#define TRACE_ERROR_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
|
||||
#define TRACE_ERROR_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_ERROR_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_ERROR_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#else
|
||||
#define TRACE_ERROR(s)
|
||||
#define TRACE_ERROR_1(s,v1)
|
||||
#define TRACE_ERROR_2(s,v1,v2)
|
||||
#define TRACE_ERROR_3(s,v1,v2,v3)
|
||||
#define TRACE_ERROR_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_ERROR_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_ERROR_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#endif
|
||||
|
||||
#if SAMA_SDMMC_TRACE_LEVEL >= 4
|
||||
#define TRACE_DEBUG(s) TRACE(s)
|
||||
#define TRACE_DEBUG_1(s,v1) TRACE_1(s,v1)
|
||||
#define TRACE_DEBUG_2(s,v1,v2) TRACE_2(s,v1,v2)
|
||||
#define TRACE_DEBUG_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
|
||||
#define TRACE_DEBUG_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_DEBUG_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_DEBUG_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#else
|
||||
#define TRACE_DEBUG(s)
|
||||
#define TRACE_DEBUG_1(s,v1)
|
||||
#define TRACE_DEBUG_2(s,v1,v2)
|
||||
#define TRACE_DEBUG_3(s,v1,v2,v3)
|
||||
#define TRACE_DEBUG_4(s,v1,v2,v3,v4)
|
||||
#define TRACE_DEBUG_5(s,v1,v2,v3,v4,v5)
|
||||
#define TRACE_DEBUG_6(s,v1,v2,v3,v4,v5,v6)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* CH_SDMMC_TRACE_H_ */
|
|
@ -1,20 +0,0 @@
|
|||
# Configuration files directory
|
||||
ifeq ($(CONFDIR),)
|
||||
CONFDIR = .
|
||||
endif
|
||||
|
||||
MCUCONF := $(strip $(shell cat $(CONFDIR)/mcuconf.h | egrep -e "\#define"))
|
||||
|
||||
ifneq ($(findstring SAMA_USE_SDMMC TRUE,$(MCUCONF)),)
|
||||
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1
|
||||
|
||||
endif
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef SAMA_SDMMC_CONF_H
|
||||
#define SAMA_SDMMC_CONF_H
|
||||
|
||||
#include "ch_sdmmc_sama5d2.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef SAMA_SDMMC_SDMMCDRIVER_IRQ_PRIORITY
|
||||
#define SAMA_SDMMC_SDMMCDRIVER_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
#ifndef SAMA_SDMMC_TRACE
|
||||
#define SAMA_SDMMC_TRACE 0
|
||||
#endif
|
||||
|
||||
#ifndef SAMA_SDMMC_TRACE_LEVEL
|
||||
#define SAMA_SDMMC_TRACE_LEVEL 5
|
||||
#endif
|
||||
|
||||
/** Default block size for SD/MMC access */
|
||||
#ifndef SDMMC_BLOCK_SIZE
|
||||
#define SDMMC_BLOCK_SIZE 512
|
||||
#endif
|
||||
|
||||
|
||||
#endif //SAMA_SDMMC_CONF_H
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sama_sdmmc_lld.c
|
||||
* @brief PLATFORM SDMMC driver
|
||||
*
|
||||
* @addtogroup SDMMC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "ccportab.h"
|
||||
|
||||
#if (SAMA_USE_SDMMC == TRUE) || defined(__DOXYGEN__)
|
||||
#include <string.h>
|
||||
#include "sama_sdmmc_lld.h"
|
||||
#include "ch_sdmmc_device.h"
|
||||
#include "ch_sdmmc_sd.h"
|
||||
#include "ch_sdmmc_sdio.h"
|
||||
#include "ch_sdmmc_trace.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SDMMC1 driver identifier.
|
||||
*/
|
||||
#if (PLATFORM_SDMMC_USE_SDMMC1 == TRUE) || defined(__DOXYGEN__)
|
||||
SdmmcDriver SDMMCD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
#if (PLATFORM_SDMMC_USE_SDMMC1 == TRUE)
|
||||
OSAL_IRQ_HANDLER(SAMA_SDMMCD1_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
osalSysLockFromISR();
|
||||
sdmmc_device_poll(&SDMMCD1);
|
||||
osalSysUnlockFromISR();
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Low level SDMMC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sdmmcInit(void)
|
||||
{
|
||||
#if PLATFORM_SDMMC_USE_SDMMC1 == TRUE
|
||||
/* Driver initialization.*/
|
||||
sdmmcObjectInit(&SDMMCD1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the SDMMC peripheral.
|
||||
*
|
||||
* @param[in] sdmmcp pointer to the @p SdmmcDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sdmmcStart(SdmmcDriver *sdmmcp, const SamaSDMMCConfig *config)
|
||||
{
|
||||
|
||||
uint8_t rc;
|
||||
|
||||
sdmmcp->config = config;
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX0, (ID_SDMMC0 + sdmmcp->config->slot_id) , SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
sdmmcp->card.EXT = sdmmcp->config->bp;
|
||||
sdmmcp->card.SSR = &sdmmcp->config->bp[EXT_SIZE];
|
||||
sdmmcp->card.SCR = &sdmmcp->config->bp[EXT_SIZE + SSR_SIZE];
|
||||
sdmmcp->card.sandbox1 =&sdmmcp->config->bp[EXT_SIZE + SSR_SIZE + SCR_SIZE];
|
||||
sdmmcp->card.sandbox2 = &sdmmcp->config->bp[EXT_SIZE + SSR_SIZE + SCR_SIZE + SB1_SIZE];
|
||||
|
||||
|
||||
rc = sdmmc_device_lowlevelcfg(sdmmcp);
|
||||
|
||||
|
||||
if (rc) {
|
||||
|
||||
//initialize
|
||||
sdmmc_device_initialize(sdmmcp);
|
||||
|
||||
if (!sdmmcp->use_polling) {
|
||||
#if (PLATFORM_SDMMC_USE_SDMMC1 == TRUE)
|
||||
aicSetSourcePriority( (ID_SDMMC0 + sdmmcp->config->slot_id) ,SAMA_SDMMC_SDMMCDRIVER_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_SDMMC0 + sdmmcp->config->slot_id,SAMA_SDMMCD1_HANDLER);
|
||||
aicEnableInt( (ID_SDMMC0 + sdmmcp->config->slot_id) );
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
TRACE_ERROR("Cannot init board for MMC\r\n");
|
||||
sdmmcp->state = MCID_INIT_ERROR;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SDMMC peripheral.
|
||||
*
|
||||
* @param[in] sdmmcp pointer to the @p SdmmcDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
|
||||
void sdmmcStop(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
|
||||
|
||||
if (sdmmcp->state != MCID_OFF) {
|
||||
/* Resets the peripheral.*/
|
||||
|
||||
/* Disables the peripheral.*/
|
||||
aicDisableInt( (ID_SDMMC0 + sdmmcp->config->slot_id) );
|
||||
|
||||
if (sdmmcp->config->slot_id == SDMMC_SLOT0) {
|
||||
pmcDisableSDMMC0();
|
||||
} else if (sdmmcp->config->slot_id == SDMMC_SLOT1) {
|
||||
pmcDisableSDMMC1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief sends a command .
|
||||
*
|
||||
* @param[in] sdmmcp pointer to the @p SdmmcDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint8_t sdmmcSendCmd(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
|
||||
uint32_t err;
|
||||
|
||||
uint8_t bRc;
|
||||
|
||||
if (sdmmcp->cmd.bCmd != 55) {
|
||||
TRACE_INFO_2("Cmd%u(%lx)\n\r", sdmmcp->cmd.bCmd, sdmmcp->cmd.dwArg);
|
||||
}
|
||||
|
||||
bRc = sdmmc_device_command(sdmmcp);
|
||||
|
||||
|
||||
{
|
||||
/* Poll command status.
|
||||
* The driver is responsible for detecting and reporting
|
||||
* timeout conditions. Here we only start a backup timer, in
|
||||
* case the driver or the peripheral meets an unexpected
|
||||
* condition. Mind that defining how long a command such as
|
||||
* WRITE_MULTIPLE_BLOCK could take in total may only lead to an
|
||||
* experimental value, lesser than the unrealistic theoretical
|
||||
* maximum.
|
||||
* Abort the command if the driver is still busy after 30s,
|
||||
* which equals 30*1000 system ticks. */
|
||||
|
||||
|
||||
sdmmcp->control_param = 1;
|
||||
sdmmcp->timeout_elapsed = 0;
|
||||
sdmmcp->timeout_ticks = 30*1000;
|
||||
sdmmc_device_startTimeCount(sdmmcp);
|
||||
|
||||
do
|
||||
{
|
||||
err = sdmmc_device_control(sdmmcp, SDMMC_IOCTL_BUSY_CHECK);
|
||||
sdmmc_device_checkTimeCount(sdmmcp);
|
||||
}
|
||||
while (sdmmcp->control_param && err == SDMMC_OK && !sdmmcp->timeout_elapsed);
|
||||
|
||||
if (err != SDMMC_OK) {
|
||||
sdmmcp->cmd.bStatus = (uint8_t)err;
|
||||
}
|
||||
else if (sdmmcp->control_param) {
|
||||
sdmmcp->control_param = 0;
|
||||
|
||||
sdmmc_device_control(sdmmcp, SDMMC_IOCTL_CANCEL_CMD);
|
||||
|
||||
sdmmcp->cmd.bStatus = SDMMC_NO_RESPONSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bRc = sdmmcp->cmd.bStatus;
|
||||
|
||||
if (bRc == SDMMC_CHANGED) {
|
||||
TRACE_DEBUG_2("Changed Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
|
||||
}
|
||||
else if (bRc != SDMMC_OK) {
|
||||
TRACE_DEBUG_2("OK Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
|
||||
}
|
||||
else if (sdmmcp->cmd.cmdOp.bmBits.respType == 1 && sdmmcp->cmd.pResp) {
|
||||
TRACE_DEBUG_2("Resp Cmd%u st %lx\n\r", sdmmcp->cmd.bCmd, *sdmmcp->cmd.pResp);
|
||||
}
|
||||
|
||||
return bRc;
|
||||
}
|
||||
|
||||
|
||||
void sdmmcObjectInit(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
sdmmcp->state = MCID_OFF;
|
||||
sdmmcp->timeout_elapsed = -1;
|
||||
sdmmcp->config = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool sdmmcOpenDevice(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
uint8_t rc;
|
||||
|
||||
rc = sdmmc_device_start(sdmmcp);
|
||||
|
||||
if (rc != SDMMC_OK) {
|
||||
TRACE_INFO_1("SD/MMC device initialization failed: %d\n\r", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sdmmc_device_identify(sdmmcp) != SDMMC_OK) {
|
||||
return false;
|
||||
}
|
||||
TRACE_INFO("SD/MMC device initialization successful\n\r");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdmmcCloseDevice(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
sdmmc_device_deInit(sdmmcp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdmmcShowDeviceInfo(SdmmcDriver *sdmmcp)
|
||||
{
|
||||
sSdCard *pSd =&sdmmcp->card;
|
||||
TRACE_INFO("Show Device Info:\n\r");
|
||||
|
||||
#ifndef SDMMC_TRIM_INFO
|
||||
const uint8_t card_type = sdmmcp->card.bCardType;
|
||||
TRACE_INFO_1("Card Type: %d\n\r", card_type);
|
||||
#endif
|
||||
TRACE_INFO("Dumping Status ... \n\r");
|
||||
SD_DumpStatus(pSd);
|
||||
#ifndef SDMMC_TRIM_INFO
|
||||
if (card_type & CARD_TYPE_bmSDMMC)
|
||||
SD_DumpCID(pSd);
|
||||
if (card_type & CARD_TYPE_bmSD) {
|
||||
SD_DumpSCR(pSd->SCR);
|
||||
SD_DumpSSR(pSd->SSR);
|
||||
}
|
||||
if (card_type & CARD_TYPE_bmSDMMC)
|
||||
SD_DumpCSD(pSd);
|
||||
#ifndef SDMMC_TRIM_MMC
|
||||
if (card_type & CARD_TYPE_bmMMC)
|
||||
SD_DumpExtCSD(pSd->EXT);
|
||||
#endif
|
||||
#ifndef SDMMC_TRIM_SDIO
|
||||
if (card_type & CARD_TYPE_bmSDIO)
|
||||
SDIO_DumpCardInformation(sdmmcp);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CC_WEAK sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp)
|
||||
{
|
||||
(void)index;
|
||||
(void)sdmmcp;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* SAMA_USE_SDMMC == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sama_sdmmc_lld.h
|
||||
* @brief PLATFORM SDMMC subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup SDMMC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_SDMMC_LLD_H
|
||||
#define SAMA_SDMMC_LLD_H
|
||||
|
||||
#if (SAMA_USE_SDMMC == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "ch_sdmmc.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name PLATFORM configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief PLATFORM_SDMMC_USE_SDMMC1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for PLATFORM_SDMMC_USE_SDMMC1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(PLATFORM_SDMMC_USE_SDMMC1) || defined(__DOXYGEN__)
|
||||
#define PLATFORM_SDMMC_USE_SDMMC1 FALSE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
MCID_OFF, /**< Device not powered */
|
||||
MCID_IDLE, /**< Idle */
|
||||
MCID_LOCKED, /**< Locked for specific slot */
|
||||
MCID_CMD, /**< Processing the command */
|
||||
MCID_ERROR, /**< Command error */
|
||||
MCID_INIT_ERROR
|
||||
}sdmmcstate_t;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
sdmmcslots_t slot_id;
|
||||
|
||||
uint8_t * bp;
|
||||
|
||||
uint32_t * dma_table;
|
||||
uint32_t dma_table_size;
|
||||
|
||||
} SamaSDMMCConfig;
|
||||
|
||||
|
||||
struct SamaSDMMCDriver
|
||||
{
|
||||
volatile sdmmcstate_t state;
|
||||
const SamaSDMMCConfig *config;
|
||||
|
||||
Sdmmc * regs; /* set of SDMMC hardware registers */
|
||||
|
||||
uint32_t tctimer_id; /* Timer/Counter peripheral ID (ID_TCx) */
|
||||
|
||||
|
||||
uint32_t dev_freq; /* frequency of clock provided to memory
|
||||
* device, in Hz */
|
||||
|
||||
sSdmmcCommand cmd;
|
||||
sSdCard card;
|
||||
|
||||
|
||||
uint16_t blk_index; /* count of data blocks tranferred already,
|
||||
* in the context of the command and data
|
||||
* transfer being executed */
|
||||
|
||||
uint8_t resp_len; /* size of the response, once retrieved,
|
||||
* in the context of the command being
|
||||
* executed, expressed in 32-bit words */
|
||||
uint8_t tim_mode; /* timing mode aka bus speed mode */
|
||||
uint16_t blk_size; /* max data block size, in bytes */
|
||||
bool use_polling; /* polling mode */
|
||||
bool cmd_line_released; /* handled the Command Complete event */
|
||||
bool dat_lines_released; /* handled the Transfer Complete event */
|
||||
bool expect_auto_end; /* waiting for completion of Auto CMD12 */
|
||||
bool use_set_blk_cnt; /* implicit SET_BLOCK_COUNT command */
|
||||
|
||||
uint32_t control_param;
|
||||
uint32_t timeout_ticks;
|
||||
int8_t timeout_elapsed;
|
||||
systime_t time,now;
|
||||
|
||||
rtcnt_t timeout_cycles;
|
||||
rtcnt_t start_cycles;
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef struct SamaSDMMCDriver SdmmcDriver;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (PLATFORM_SDMMC_USE_SDMMC1 == TRUE)
|
||||
extern SdmmcDriver SDMMCD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void sdmmcInit(void);
|
||||
void sdmmcObjectInit(SdmmcDriver *sdmmcp);
|
||||
void sdmmcStart(SdmmcDriver *sdmmcp, const SamaSDMMCConfig *config);
|
||||
void sdmmcStop(SdmmcDriver *sdmmcp);
|
||||
uint8_t sdmmcSendCmd(SdmmcDriver *sdmmcp);
|
||||
bool sdmmcOpenDevice(SdmmcDriver *sdmmcp);
|
||||
bool sdmmcCloseDevice(SdmmcDriver *sdmmcp);
|
||||
bool sdmmcShowDeviceInfo(SdmmcDriver *sdmmcp);
|
||||
bool sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_SDMMC == TRUE */
|
||||
|
||||
#endif /* SAMA_SDMMC_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SPIv1
|
|
@ -1,968 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_spi_lld.c
|
||||
* @brief SAMA SPI subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup SPI
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_SPI || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on SPI registers block.
|
||||
*
|
||||
* @param[in] spip pointer to a SPI register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define spiEnableWP(spip) { \
|
||||
spip->SPI_WPMR = SPI_WPMR_WPKEY_PASSWD | SPI_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on SPI registers block.
|
||||
*
|
||||
* @param[in] spip pointer to a SPI register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define spiDisableWP(spip) { \
|
||||
spip->SPI_WPMR = SPI_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SPI0 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_SPI0 || defined(__DOXYGEN__)
|
||||
SPIDriver SPID0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_SPI1 || defined(__DOXYGEN__)
|
||||
SPIDriver SPID1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM0 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_FLEXCOM0 || defined(__DOXYGEN__)
|
||||
SPIDriver FSPID0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM1 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_FLEXCOM1 || defined(__DOXYGEN__)
|
||||
SPIDriver FSPID1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM2 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_FLEXCOM2 || defined(__DOXYGEN__)
|
||||
SPIDriver FSPID2;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM3 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_FLEXCOM3 || defined(__DOXYGEN__)
|
||||
SPIDriver FSPID3;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM4 driver identifier.
|
||||
*/
|
||||
#if SAMA_SPI_USE_FLEXCOM4 || defined(__DOXYGEN__)
|
||||
SPIDriver FSPID4;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static const CACHE_ALIGNED uint8_t dummytx = 0xFFU;
|
||||
CACHE_ALIGNED static uint8_t dummyrx;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Shared end-of-rx service routine.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*/
|
||||
static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_SPI_DMA_ERROR_HOOK)
|
||||
if ((flags & (XDMAC_CIS_RBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_SPI_DMA_ERROR_HOOK(spip);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
/* Stop everything.*/
|
||||
dmaChannelDisable(spip->dmatx);
|
||||
dmaChannelDisable(spip->dmarx);
|
||||
|
||||
#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
|
||||
/* D-Cache is enabled */
|
||||
/* No operation for dummyrx */
|
||||
if ((uint32_t) spip->rxbuf != (uint32_t) &dummyrx)
|
||||
cacheInvalidateRegion(spip->rxbuf, spip->rxbytes);
|
||||
#endif
|
||||
|
||||
/* Portable SPI ISR code defined in the high level driver, note, it is
|
||||
a macro.*/
|
||||
_spi_isr_code(spip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shared end-of-tx service routine.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*/
|
||||
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_SPI_DMA_ERROR_HOOK)
|
||||
(void)spip;
|
||||
if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_SPI_DMA_ERROR_HOOK(spip);
|
||||
}
|
||||
#else
|
||||
(void)spip;
|
||||
(void)flags;
|
||||
#endif
|
||||
}
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level SPI driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_init(void) {
|
||||
|
||||
#if SAMA_SPI_USE_SPI0
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SPI0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&SPID0);
|
||||
SPID0.spi = SPI0;
|
||||
SPID0.flexcom = NULL;
|
||||
SPID0.dmarx = NULL;
|
||||
SPID0.dmatx = NULL;
|
||||
SPID0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_SPI0_RX);
|
||||
SPID0.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_SPI0_TX);
|
||||
#endif /* SAMA_SPI_USE_SPI0 */
|
||||
|
||||
#if SAMA_SPI_USE_SPI1
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SPI1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&SPID1);
|
||||
SPID1.spi = SPI1;
|
||||
SPID1.flexcom = NULL;
|
||||
SPID1.dmarx = NULL;
|
||||
SPID1.dmatx = NULL;
|
||||
SPID1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_SPI1_RX);
|
||||
SPID1.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_SPI1_TX);
|
||||
#endif /* SAMA_SPI_USE_SPI1 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM0
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_FLEXCOM0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&FSPID0);
|
||||
FSPID0.spi = FCOMSPI0;
|
||||
FSPID0.flexcom = FLEXCOM0;
|
||||
FSPID0.dmarx = NULL;
|
||||
FSPID0.dmatx = NULL;
|
||||
FSPID0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM0_RX);
|
||||
FSPID0.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM0_TX);
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM0 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM1
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_FLEXCOM1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&FSPID1);
|
||||
FSPID1.spi = FCOMSPI1;
|
||||
FSPID1.flexcom = FLEXCOM1;
|
||||
FSPID1.dmarx = NULL;
|
||||
FSPID1.dmatx = NULL;
|
||||
FSPID1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM1_RX);
|
||||
FSPID1.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM1_TX);
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM1 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM2
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_FLEXCOM2, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&FSPID2);
|
||||
FSPID2.spi = FCOMSPI2;
|
||||
FSPID2.flexcom = FLEXCOM2;
|
||||
FSPID2.dmarx = NULL;
|
||||
FSPID2.dmatx = NULL;
|
||||
FSPID2.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM2_RX);
|
||||
FSPID2.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM2_TX);
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM2 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM3
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_FLEXCOM3, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&FSPID3);
|
||||
FSPID3.spi = FCOMSPI3;
|
||||
FSPID3.flexcom = FLEXCOM3;
|
||||
FSPID3.dmarx = NULL;
|
||||
FSPID3.dmatx = NULL;
|
||||
FSPID3.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM3_RX);
|
||||
FSPID3.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM3_TX);
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM3 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM4
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_FLEXCOM4, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
spiObjectInit(&FSPID4);
|
||||
FSPID4.spi = FCOMSPI4;
|
||||
FSPID4.flexcom = FLEXCOM4;
|
||||
FSPID4.dmarx = NULL;
|
||||
FSPID4.dmatx = NULL;
|
||||
FSPID4.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF0 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_INCREMENTED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM4_RX);
|
||||
FSPID4.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SIXTEEN |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_FLEXCOM4_TX);
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM4 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the SPI peripheral.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_start(SPIDriver *spip) {
|
||||
|
||||
/* Configures the peripheral.*/
|
||||
|
||||
if (spip->state == SPI_STOP) {
|
||||
|
||||
#if SAMA_SPI_USE_SPI0
|
||||
if (&SPID0 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
|
||||
#if SAMA_SPI0_USE_GCLK
|
||||
#if SAMA_SPI0_GCLK_DIV > 256
|
||||
#error "SPI0 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_SPI0, SAMA_SPI0_GCLK_SOURCE, SAMA_SPI0_GCLK_DIV);
|
||||
pmcEnableGclk(ID_SPI0);
|
||||
#endif /* SAMA_SPI0_USE_GCLK */
|
||||
|
||||
/* Enable SPI0 clock */
|
||||
pmcEnableSPI0();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_SPI0 */
|
||||
#if SAMA_SPI_USE_SPI1
|
||||
if (&SPID1 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_SPI1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_SPI1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
|
||||
#if SAMA_SPI1_USE_GCLK
|
||||
#if SAMA_SPI1_GCLK_DIV > 256
|
||||
#error "SPI1 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_SPI1, SAMA_SPI1_GCLK_SOURCE, SAMA_SPI1_GCLK_DIV);
|
||||
pmcEnableGclk(ID_SPI1);
|
||||
#endif /* SAMA_SPI1_USE_GCLK */
|
||||
|
||||
/* Enable SPI1 clock */
|
||||
pmcEnableSPI1();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_SPI1 */
|
||||
#if SAMA_SPI_USE_FLEXCOM0
|
||||
if (&FSPID0 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_FLEXCOM0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_FLEXCOM0_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
/* Enabling SPI on FLEXCOM */
|
||||
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
|
||||
|
||||
#if SAMA_FSPI0_USE_GCLK
|
||||
#if SAMA_FSPI0_GCLK_DIV > 256
|
||||
#error "FSPI0 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_FLEXCOM0, SAMA_FSPI0_GCLK_SOURCE, SAMA_FSPI0_GCLK_DIV);
|
||||
pmcEnableGclk(ID_FLEXCOM0);
|
||||
#endif /* SAMA_FSPI0_USE_GCLK */
|
||||
|
||||
/* Enable FLEXCOM0 clock */
|
||||
pmcEnableFLEXCOM0();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM0 */
|
||||
#if SAMA_SPI_USE_FLEXCOM1
|
||||
if (&FSPID1 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_FLEXCOM1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_FLEXCOM1_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
/* Enabling SPI on FLEXCOM */
|
||||
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
|
||||
|
||||
#if SAMA_FSPI1_USE_GCLK
|
||||
#if SAMA_FSPI1_GCLK_DIV > 256
|
||||
#error "FSPI1 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_FLEXCOM1, SAMA_FSPI1_GCLK_SOURCE, SAMA_FSPI1_GCLK_DIV);
|
||||
pmcEnableGclk(ID_FLEXCOM1);
|
||||
#endif /* SAMA_FSPI1_USE_GCLK */
|
||||
|
||||
/* Enable FLEXCOM1 clock */
|
||||
pmcEnableFLEXCOM1();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM1 */
|
||||
#if SAMA_SPI_USE_FLEXCOM2
|
||||
if (&FSPID2 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_FLEXCOM2_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_FLEXCOM2_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
/* Enabling SPI on FLEXCOM */
|
||||
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
|
||||
|
||||
#if SAMA_FSPI2_USE_GCLK
|
||||
#if SAMA_FSPI2_GCLK_DIV > 256
|
||||
#error "FSPI2 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_FLEXCOM2, SAMA_FSPI2_GCLK_SOURCE, SAMA_FSPI2_GCLK_DIV);
|
||||
pmcEnableGclk(ID_FLEXCOM2);
|
||||
#endif /* SAMA_FSPI2_USE_GCLK */
|
||||
|
||||
/* Enable FLEXCOM2 clock */
|
||||
pmcEnableFLEXCOM2();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM2 */
|
||||
#if SAMA_SPI_USE_FLEXCOM3
|
||||
if (&FSPID3 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_FLEXCOM3_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_FLEXCOM3_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
/* Enabling SPI on FLEXCOM */
|
||||
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
|
||||
|
||||
#if SAMA_FSPI3_USE_GCLK
|
||||
#if SAMA_FSPI3_GCLK_DIV > 256
|
||||
#error "FSPI3 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_FLEXCOM3, SAMA_FSPI3_GCLK_SOURCE, SAMA_FSPI3_GCLK_DIV);
|
||||
pmcEnableGclk(ID_FLEXCOM3);
|
||||
#endif /* SAMA_FSPI3_USE_GCLK */
|
||||
|
||||
/* Enable FLEXCOM3 clock */
|
||||
pmcEnableFLEXCOM3();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM3 */
|
||||
#if SAMA_SPI_USE_FLEXCOM4
|
||||
if (&FSPID4 == spip) {
|
||||
spip->dmarx = dmaChannelAllocate(SAMA_SPI_FLEXCOM4_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_rx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmarx != NULL, "no channel allocated");
|
||||
|
||||
spip->dmatx = dmaChannelAllocate(SAMA_SPI_FLEXCOM4_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
|
||||
(void *)spip);
|
||||
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
|
||||
/* Enabling SPI on FLEXCOM */
|
||||
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
|
||||
|
||||
#if SAMA_FSPI4_USE_GCLK
|
||||
#if SAMA_FSPI4_GCLK_DIV > 256
|
||||
#error "FSPI4 GCLK divider out of range"
|
||||
#endif
|
||||
pmcConfigGclk(ID_FLEXCOM4, SAMA_FSPI4_GCLK_SOURCE, SAMA_FSPI4_GCLK_DIV);
|
||||
pmcEnableGclk(ID_FLEXCOM4);
|
||||
#endif /* SAMA_FSPI4_USE_GCLK */
|
||||
|
||||
/* Enable FLEXCOM4 clock */
|
||||
pmcEnableFLEXCOM4();
|
||||
}
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM4 */
|
||||
}
|
||||
|
||||
/* Set mode */
|
||||
dmaChannelSetMode(spip->dmarx, spip->rxdmamode);
|
||||
dmaChannelSetMode(spip->dmatx, spip->txdmamode);
|
||||
|
||||
/* Disable write protection */
|
||||
spiDisableWP(spip->spi);
|
||||
|
||||
/* Execute a software reset of the SPI twice */
|
||||
spip->spi->SPI_CR = SPI_CR_SWRST;
|
||||
spip->spi->SPI_CR = SPI_CR_SWRST;
|
||||
|
||||
/* SPI configuration */
|
||||
spip->spi->SPI_MR = SPI_MR_MSTR | SPI_MR_WDRBT | spip->config->mr;
|
||||
spip->spi->SPI_MR &= ~SPI_MR_PCS_Msk;
|
||||
spip->spi->SPI_MR |= SPI_PCS(spip->config->npcs);
|
||||
spip->spi->SPI_CSR[spip->config->npcs] = spip->config->csr;
|
||||
|
||||
/* if SPI_CSRx_BITS > 8, dma is set to 16 bits */
|
||||
if (((spip->spi->SPI_CSR[spip->config->npcs] >> 4) & 0xF) > 0) {
|
||||
dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_DWIDTH_HALFWORD);
|
||||
dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DWIDTH_HALFWORD);
|
||||
}
|
||||
|
||||
/* Enable SPI */
|
||||
spip->spi->SPI_CR |= SPI_CR_SPIEN;
|
||||
/* Enable write protection. */
|
||||
spiEnableWP(spip->spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SPI peripheral.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_stop(SPIDriver *spip) {
|
||||
|
||||
if (spip->state == SPI_READY) {
|
||||
/* Disable write protection */
|
||||
spiDisableWP(spip->spi);
|
||||
/* Reset SPI */
|
||||
spip->spi->SPI_MR = 0;
|
||||
spip->spi->SPI_CSR[spip->config->npcs] = 0;
|
||||
/* Disable SPI */
|
||||
spip->spi->SPI_CR |= SPI_CR_SPIDIS;
|
||||
/* Enable write protection */
|
||||
spiEnableWP(spip->spi);
|
||||
|
||||
dmaChannelRelease(spip->dmarx);
|
||||
dmaChannelRelease(spip->dmatx);
|
||||
|
||||
#if SAMA_SPI_USE_SPI0
|
||||
if (&SPID0 == spip)
|
||||
/* Disable SPI0 clock */
|
||||
pmcDisableSPI0();
|
||||
#if SAMA_SPI0_USE_GCLK
|
||||
pmcDisableGclk(ID_SPI0);
|
||||
#endif /* SAMA_SPI0_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_SPI0 */
|
||||
|
||||
#if SAMA_SPI_USE_SPI1
|
||||
if (&SPID1 == spip)
|
||||
/* Disable SPI1 clock */
|
||||
pmcDisableSPI1();
|
||||
|
||||
#if SAMA_SPI1_USE_GCLK
|
||||
pmcDisableGclk(ID_SPI1);
|
||||
#endif /* SAMA_SPI1_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_SPI1 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM0
|
||||
if (&FSPID0 == spip)
|
||||
/* Disable FLEXCOM0 clock */
|
||||
pmcDisableFLEXCOM0();
|
||||
|
||||
#if SAMA_FSPI0_USE_GCLK
|
||||
pmcDisableGclk(ID_FLEXCOM0);
|
||||
#endif /* SAMA_FSPI0_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM0 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM1
|
||||
if (&FSPID1 == spip)
|
||||
/* Disable FLEXCOM1 clock */
|
||||
pmcDisableFLEXCOM1();
|
||||
|
||||
#if SAMA_FSPI1_USE_GCLK
|
||||
pmcDisableGclk(ID_FLEXCOM1);
|
||||
#endif /* SAMA_FSPI1_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM1 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM2
|
||||
if (&FSPID2 == spip)
|
||||
/* Disable FLEXCOM2 clock */
|
||||
pmcDisableFLEXCOM2();
|
||||
|
||||
#if SAMA_FSPI2_USE_GCLK
|
||||
pmcDisableGclk(ID_FLEXCOM2);
|
||||
#endif /* SAMA_FSPI2_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM2 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM3
|
||||
if (&FSPID3 == spip)
|
||||
/* Disable FLEXCOM3 clock */
|
||||
pmcDisableFLEXCOM3();
|
||||
|
||||
#if SAMA_FSPI3_USE_GCLK
|
||||
pmcDisableGclk(ID_FLEXCOM3);
|
||||
#endif /* SAMA_FSPI3_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM3 */
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM4
|
||||
if (&FSPID4 == spip)
|
||||
/* Disable FLEXCOM4 clock */
|
||||
pmcDisableFLEXCOM4();
|
||||
|
||||
#if SAMA_FSPI4_USE_GCLK
|
||||
pmcDisableGclk(ID_FLEXCOM4);
|
||||
#endif /* SAMA_FSPI4_USE_GCLK */
|
||||
|
||||
#endif /* SAMA_SPI_USE_FLEXCOM4 */
|
||||
}
|
||||
|
||||
spip->txbuf = NULL;
|
||||
spip->rxbuf = NULL;
|
||||
spip->rxbytes = 0;
|
||||
}
|
||||
|
||||
#if (SPI_SELECT_MODE == (SPI_SELECT_MODE_LLD || SPI_SELECT_MODE_PAD || \
|
||||
SPI_SELECT_MODE_PORT || SPI_SELECT_MODE_LINE)) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Asserts the slave select signal and prepares for transfers.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_select(SPIDriver *spip) {
|
||||
/* No implementation on SAMA.*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deasserts the slave select signal.
|
||||
* @details The previously selected peripheral is unselected.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_unselect(SPIDriver *spip) {
|
||||
/* No implementation on SAMA.*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Exchanges data on the SPI bus.
|
||||
* @details This asynchronous function starts a simultaneous transmit/receive
|
||||
* operation.
|
||||
* @post At the end of the operation the configured callback is invoked.
|
||||
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
||||
* equal to 8 bits else it is organized as uint16_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to be exchanged
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
* @param[out]rxbuf the pointer to the receive buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_exchange(SPIDriver *spip, size_t n,
|
||||
const void *txbuf, void *rxbuf) {
|
||||
|
||||
spip->txbuf = txbuf;
|
||||
spip->rxbuf = rxbuf;
|
||||
spip->rxbytes = n;
|
||||
|
||||
#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
|
||||
|
||||
osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned");
|
||||
osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned");
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
*/
|
||||
if (n & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) rxbuf, n);
|
||||
}
|
||||
/* Cache is enabled */
|
||||
cacheCleanRegion((uint8_t *) txbuf, n);
|
||||
#endif /* SAMA_SPI_CACHE_USER_MANAGED */
|
||||
|
||||
/* Writing channel */
|
||||
/* Change mode to incremented address for dummytx */
|
||||
dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM);
|
||||
dmaChannelSetSource(spip->dmatx, txbuf);
|
||||
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
|
||||
dmaChannelSetTransactionSize(spip->dmatx, n);
|
||||
|
||||
/* Reading channel */
|
||||
/* Change mode to incremented address */
|
||||
dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM);
|
||||
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
|
||||
dmaChannelSetDestination(spip->dmarx, rxbuf);
|
||||
dmaChannelSetTransactionSize(spip->dmarx, n);
|
||||
|
||||
dmaChannelEnable(spip->dmarx);
|
||||
dmaChannelEnable(spip->dmatx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends data over the SPI bus.
|
||||
* @details This asynchronous function starts a transmit operation.
|
||||
* @post At the end of the operation the configured callback is invoked.
|
||||
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
||||
* equal to 8 bits else it is organized as uint16_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to send
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
|
||||
|
||||
spip->txbuf = txbuf;
|
||||
spip->rxbuf = &dummyrx;
|
||||
spip->rxbytes = n;
|
||||
|
||||
#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
|
||||
|
||||
osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned");
|
||||
|
||||
/* Cache is enabled */
|
||||
cacheCleanRegion((uint8_t *) txbuf, n);
|
||||
#endif /* SAMA_SPI_CACHE_USER_MANAGED */
|
||||
|
||||
/* Writing channel */
|
||||
|
||||
/* Change mode to incremented address for dummytx */
|
||||
dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM);
|
||||
|
||||
dmaChannelSetSource(spip->dmatx, txbuf);
|
||||
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
|
||||
dmaChannelSetTransactionSize(spip->dmatx, n);
|
||||
|
||||
/* Reading channel */
|
||||
|
||||
/* Change mode from incremented to fixed address for dummyrx */
|
||||
dmaChannelSetMode(spip->dmarx, spip->rxdmamode & ~XDMAC_CC_DAM_INCREMENTED_AM);
|
||||
|
||||
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
|
||||
dmaChannelSetDestination(spip->dmarx, &dummyrx);
|
||||
dmaChannelSetTransactionSize(spip->dmarx, n);
|
||||
|
||||
/* Enable channel. */
|
||||
dmaChannelEnable(spip->dmarx);
|
||||
dmaChannelEnable(spip->dmatx);
|
||||
|
||||
/* Waiting TXEMPTY flag */
|
||||
while (!(spip->spi->SPI_SR & SPI_SR_TXEMPTY)) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receives data from the SPI bus.
|
||||
* @details This asynchronous function starts a receive operation.
|
||||
* @post At the end of the operation the configured callback is invoked.
|
||||
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
||||
* equal to 8 bits else it is organized as uint16_t arrays.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] n number of words to receive
|
||||
* @param[out]rxbuf the pointer to the receive buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
|
||||
|
||||
spip->rxbuf = rxbuf;
|
||||
spip->rxbytes = n;
|
||||
|
||||
#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
|
||||
|
||||
osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned");
|
||||
|
||||
/*
|
||||
* If size is not multiple of cache line, clean cache region is required.
|
||||
*/
|
||||
if (n & (L1_CACHE_BYTES - 1)) {
|
||||
cacheCleanRegion((uint8_t *) rxbuf, n);
|
||||
}
|
||||
#endif /* SAMA_SPI_CACHE_USER_MANAGED */
|
||||
|
||||
/* Writing channel */
|
||||
/* Change mode from incremented to fixed address for dummytx */
|
||||
dmaChannelSetMode(spip->dmatx, spip->txdmamode & ~XDMAC_CC_SAM_INCREMENTED_AM);
|
||||
|
||||
dmaChannelSetSource(spip->dmatx, &dummytx);
|
||||
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
|
||||
dmaChannelSetTransactionSize(spip->dmatx, n);
|
||||
|
||||
/* Reading channel */
|
||||
/* Change mode to incremented address */
|
||||
dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM);
|
||||
|
||||
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
|
||||
dmaChannelSetDestination(spip->dmarx, rxbuf);
|
||||
dmaChannelSetTransactionSize(spip->dmarx, n);
|
||||
|
||||
dmaChannelEnable(spip->dmarx);
|
||||
dmaChannelEnable(spip->dmatx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges one frame using a polled wait.
|
||||
* @details This synchronous function exchanges one frame using a polled
|
||||
* synchronization method. This function is useful when exchanging
|
||||
* small amount of data on high speed channels, usually in this
|
||||
* situation is much more efficient just wait for completion using
|
||||
* polling than suspending the thread waiting for an interrupt.
|
||||
*
|
||||
* @param[in] spip pointer to the @p SPIDriver object
|
||||
* @param[in] frame the data frame to send over the SPI bus
|
||||
* @return The received data frame from the SPI bus.
|
||||
*/
|
||||
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
|
||||
|
||||
while((spip->spi->SPI_SR & SPI_SR_TXEMPTY) == 1);
|
||||
|
||||
spip->spi->SPI_TDR = (uint8_t) frame;
|
||||
|
||||
while((spip->spi->SPI_SR & SPI_SR_RDRF) == 0);
|
||||
|
||||
return (uint16_t) spip->spi->SPI_RDR;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_SPI */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -1,493 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_spi_lld.h
|
||||
* @brief SAMA SPI subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup SPI
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_SPI_LLD_H
|
||||
#define HAL_SPI_LLD_H
|
||||
|
||||
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Circular mode support flag.
|
||||
*/
|
||||
#define SPI_SUPPORTS_CIRCULAR FALSE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief SPI0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for SPI0 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_SPI0) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_SPI0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI0 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK SPI0 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI0_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI0_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI0 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_SPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI0 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_SPI0_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI0_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for SPI1 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_SPI1) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_SPI1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK SPI1 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI1_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI1_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_SPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_SPI1_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI1_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM0 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_FLEXCOM0) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_FLEXCOM0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI0 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK FSPI0 is included.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI0_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI0_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI0 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI0 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI0_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI0_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM1 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_FLEXCOM1) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_FLEXCOM1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI1 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK FSPI1 is included.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI1_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI1_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI1 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI1 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI1_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI1_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM2 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_FLEXCOM2) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_FLEXCOM2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI2 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK FSPI2 is included.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI2_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI2_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI2 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI2_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI2_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI2 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI2_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI2_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM3 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_FLEXCOM3) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_FLEXCOM3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI3 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK FSPI3 is included.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI3_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI3_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI3 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI3_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI3_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI3 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI3_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI3_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI FLEXCOM4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM4 is included.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_USE_FLEXCOM4) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_USE_FLEXCOM4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI4 Generic clock enable.
|
||||
* @details If set to @p TRUE the support for GCLK FSPI4 is included.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI4_USE_GCLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI4_USE_GCLK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI4 Generic clock source.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI4_GCLK_SOURCE) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI4_GCLK_SOURCE SAMA_GCLK_MCK_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FSPI4 Generic clock div.
|
||||
*/
|
||||
#if !defined(SAMA_FSPI4_GCLK_DIV) || defined(__DOXYGEN__)
|
||||
#define SAMA_FSPI4_GCLK_DIV 21
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI0 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_SPI0_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI1 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_SPI1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_SPI1_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM0 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_FLEXCOM0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_FLEXCOM0_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM1 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_FLEXCOM1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_FLEXCOM1_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM2 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_FLEXCOM2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_FLEXCOM2_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM3 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_FLEXCOM3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_FLEXCOM3_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM4 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_FLEXCOM4_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_FLEXCOM4_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief SPI DMA error hook.
|
||||
* @note The default action for DMA errors is a system halt because DMA
|
||||
* error can only happen because programming errors.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SPI cache managing.
|
||||
*/
|
||||
#if !defined(SAMA_SPI_CACHE_USER_MANAGED) || defined(__DOXYGEN__)
|
||||
#define SAMA_SPI_CACHE_USER_MANAGED FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief At least an SPI unit is in use.
|
||||
*/
|
||||
#define SAMA_SPI_USE_SPI (SAMA_SPI_USE_SPI0 || \
|
||||
SAMA_SPI_USE_SPI1)
|
||||
|
||||
/**
|
||||
* @brief At least an FLEXCOM unit is in use.
|
||||
*/
|
||||
#define SAMA_SPI_USE_FLEXCOM (SAMA_SPI_USE_FLEXCOM0 || \
|
||||
SAMA_SPI_USE_FLEXCOM1 || \
|
||||
SAMA_SPI_USE_FLEXCOM2 || \
|
||||
SAMA_SPI_USE_FLEXCOM3 || \
|
||||
SAMA_SPI_USE_FLEXCOM4)
|
||||
|
||||
#if !SAMA_SPI_USE_SPI0 && !SAMA_SPI_USE_SPI1 && \
|
||||
!SAMA_SPI_USE_FLEXCOM0 && !SAMA_SPI_USE_FLEXCOM1 && \
|
||||
!SAMA_SPI_USE_FLEXCOM2 && !SAMA_SPI_USE_FLEXCOM3 && \
|
||||
!SAMA_SPI_USE_FLEXCOM4
|
||||
#error "SPI driver activated but no SPI peripheral assigned"
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of UARTx units.*/
|
||||
#if SAMA_SPI_USE_FLEXCOM0
|
||||
#if defined(SAMA_FLEXCOM0_IS_USED)
|
||||
#error "FSPID0 requires FLEXCOM0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM1
|
||||
#if defined(SAMA_FLEXCOM1_IS_USED)
|
||||
#error "FSPID1 requires FLEXCOM1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM2
|
||||
#if defined(SAMA_FLEXCOM2_IS_USED)
|
||||
#error "FSPID2 requires FLEXCOM2 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM2_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM3
|
||||
#if defined(SAMA_FLEXCOM3_IS_USED)
|
||||
#error "FSPID3 requires FLEXCOM3 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM3_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM4
|
||||
#if defined(SAMA_FLEXCOM4_IS_USED)
|
||||
#error "FSPID4 requires FLEXCOM4 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM4_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SPI_SELECT_MODE == (SPI_SELECT_MODE_LLD || SPI_SELECT_MODE_PAD || \
|
||||
SPI_SELECT_MODE_PORT || SPI_SELECT_MODE_LINE)
|
||||
#error "SPI_SELECT_MODE_NONE is supported by this driver"
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA_DMA_REQUIRED)
|
||||
#define SAMA_DMA_REQUIRED
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define spi_lld_driver_fields \
|
||||
/* Pointer to the SPIx registers block.*/ \
|
||||
Spi *spi; \
|
||||
/* Pointer to the FLEXCOMx registers block.*/ \
|
||||
Flexcom *flexcom; \
|
||||
/* Receive DMA stream.*/ \
|
||||
sama_dma_channel_t *dmarx; \
|
||||
/* Transmit DMA stream.*/ \
|
||||
sama_dma_channel_t *dmatx; \
|
||||
/* RX DMA mode bit mask.*/ \
|
||||
uint32_t rxdmamode; \
|
||||
/* TX DMA mode bit mask.*/ \
|
||||
uint32_t txdmamode; \
|
||||
/* Pointer to the TX buffer location.*/ \
|
||||
const uint8_t *txbuf; \
|
||||
/* Pointer to the RX buffer location.*/ \
|
||||
uint8_t *rxbuf; \
|
||||
/* Number of bytes in RX phase.*/ \
|
||||
size_t rxbytes;
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the SPI configuration structure.
|
||||
*/
|
||||
#define spi_lld_config_fields \
|
||||
/* The chip select line number.*/ \
|
||||
uint8_t npcs; \
|
||||
/* SPI MR register initialization data.*/ \
|
||||
uint32_t mr; \
|
||||
/* SPI CSR register initialization data.*/ \
|
||||
uint32_t csr;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
#define SPI_PCS(npcs) SPI_MR_PCS((~(1 << npcs) & 0xF))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_SPI_USE_SPI0 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver SPID0;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_SPI1 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver SPID1;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM0 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver FSPID0;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM1 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver FSPID1;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM2 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver FSPID2;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM3 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver FSPID3;
|
||||
#endif
|
||||
|
||||
#if SAMA_SPI_USE_FLEXCOM4 && !defined(__DOXYGEN__)
|
||||
extern SPIDriver FSPID4;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void spi_lld_init(void);
|
||||
void spi_lld_start(SPIDriver *spip);
|
||||
void spi_lld_stop(SPIDriver *spip);
|
||||
void spi_lld_select(SPIDriver *spip);
|
||||
void spi_lld_unselect(SPIDriver *spip);
|
||||
void spi_lld_ignore(SPIDriver *spip, size_t n);
|
||||
void spi_lld_exchange(SPIDriver *spip, size_t n,
|
||||
const void *txbuf, void *rxbuf);
|
||||
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
|
||||
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
|
||||
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_SPI */
|
||||
|
||||
#endif /* HAL_SPI_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,13 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_SERIAL TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.c
|
||||
endif
|
||||
#ifneq ($(findstring HAL_USE_UART TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c
|
||||
#endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.c
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1
|
File diff suppressed because it is too large
Load Diff
|
@ -1,567 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file USARTv1/hal_serial_lld.h
|
||||
* @brief SAMA low level serial driver header.
|
||||
*
|
||||
* @addtogroup SERIAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_SERIAL_LLD_H
|
||||
#define HAL_SERIAL_LLD_H
|
||||
|
||||
#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Advanced buffering support switch.
|
||||
* @details This constants enables the advanced buffering support in the
|
||||
* low level driver, the queue buffer is no more part of the
|
||||
* @p SerialDriver structure, each driver can have a different
|
||||
* queue size.
|
||||
*/
|
||||
#define SERIAL_ADVANCED_BUFFERING_SUPPORT TRUE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief UART0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for UART0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_UART0) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_UART0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for UART1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_UART1) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_USART1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for UART2 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_UART2) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_UART2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for UART3 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_UART3) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_UART3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for UART4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_UART4) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_UART4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_FLEXCOM0) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_FLEXCOM0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_FLEXCOM1) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_FLEXCOM1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM2 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_FLEXCOM2) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_FLEXCOM2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM3 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_FLEXCOM3) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_FLEXCOM3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_USE_FLEXCOM4) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_USE_FLEXCOM4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART0_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART1_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART2_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART3_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART4_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM0_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM1_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM2_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM3_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM4_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for UART0.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART0_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART0_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for UART0.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART0_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART0_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for UART1.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART1_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for UART1.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART1_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for UART2.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART2_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART2_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for UART2.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART2_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART2_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for UART3.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART3_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART3_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for UART3.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART3_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART3_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for UART4.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART4_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART4_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for UART4.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_UART4_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_UART4_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for FLEXCOM0.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM0_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM0_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for FLEXCOM0.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM0_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM0_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for FLEXCOM1.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM1_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM1_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for FLEXCOM1.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM1_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM1_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for FLEXCOM2.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM2_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM2_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for FLEXCOM2.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM2_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM2_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for FLEXCOM3.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM3_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM3_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for FLEXCOM3.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM3_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM3_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Input buffer size for FLEXCOM4.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM4_IN_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM4_IN_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Output buffer size for FLEXCOM4.
|
||||
*/
|
||||
#if !defined(SAMA_SERIAL_FLEXCOM4_OUT_BUF_SIZE) || defined(__DOXYGEN__)
|
||||
#define SAMA_SERIAL_FLEXCOM4_OUT_BUF_SIZE SERIAL_BUFFERS_SIZE
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief At least an UART unit is in use.
|
||||
*/
|
||||
#define SAMA_SERIAL_USE_UART (SAMA_SERIAL_USE_UART0 || \
|
||||
SAMA_SERIAL_USE_UART1 || \
|
||||
SAMA_SERIAL_USE_UART2 || \
|
||||
SAMA_SERIAL_USE_UART3 || \
|
||||
SAMA_SERIAL_USE_UART4)
|
||||
|
||||
/**
|
||||
* @brief At least an FLEXCOM unit is in use.
|
||||
*/
|
||||
#define SAMA_SERIAL_USE_FLEXCOM (SAMA_SERIAL_USE_FLEXCOM0 || \
|
||||
SAMA_SERIAL_USE_FLEXCOM1 || \
|
||||
SAMA_SERIAL_USE_FLEXCOM2 || \
|
||||
SAMA_SERIAL_USE_FLEXCOM3 || \
|
||||
SAMA_SERIAL_USE_FLEXCOM4)
|
||||
|
||||
#if !SAMA_SERIAL_USE_UART0 && !SAMA_SERIAL_USE_UART1 && \
|
||||
!SAMA_SERIAL_USE_UART2 && !SAMA_SERIAL_USE_UART3 && \
|
||||
!SAMA_SERIAL_USE_UART4 && \
|
||||
!SAMA_SERIAL_USE_FLEXCOM0 && !SAMA_SERIAL_USE_FLEXCOM1 && \
|
||||
!SAMA_SERIAL_USE_FLEXCOM2 && !SAMA_SERIAL_USE_FLEXCOM3 && \
|
||||
!SAMA_SERIAL_USE_FLEXCOM4
|
||||
#error "SERIAL driver activated but no USART/UART peripheral assigned"
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of UARTx units.*/
|
||||
#if SAMA_SERIAL_USE_UART0
|
||||
#if defined(SAMA_UART0_IS_USED)
|
||||
#error "SD0 requires UART0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_UART1
|
||||
#if defined(SAMA_UART1_IS_USED)
|
||||
#error "SD1 requires UART1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_UART2
|
||||
#if defined(SAMA_UART2_IS_USED)
|
||||
#error "SD2 requires UART2 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART2_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_UART3
|
||||
#if defined(SAMA_UART3_IS_USED)
|
||||
#error "SD3 requires UART3 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART3_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_UART4
|
||||
#if defined(SAMA_UART4_IS_USED)
|
||||
#error "SD4 requires UART4 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART4_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_FLEXCOM0
|
||||
#if defined(SAMA_FLEXCOM0_IS_USED)
|
||||
#error "FSD0 requires FLEXCOM0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_FLEXCOM1
|
||||
#if defined(SAMA_FLEXCOM1_IS_USED)
|
||||
#error "FSD1 requires FLEXCOM1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_FLEXCOM2
|
||||
#if defined(SAMA_FLEXCOM2_IS_USED)
|
||||
#error "FSD2 requires FLEXCOM2 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM2_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_FLEXCOM3
|
||||
#if defined(SAMA_FLEXCOM3_IS_USED)
|
||||
#error "FSD3 requires FLEXCOM3 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM3_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_SERIAL_USE_FLEXCOM4
|
||||
#if defined(SAMA_FLEXCOM4_IS_USED)
|
||||
#error "FSD4 requires FLEXCOM4 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM4_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SAMA Serial Driver configuration structure.
|
||||
* @details An instance of this structure must be passed to @p sdStart()
|
||||
* in order to configure and start a serial driver operations.
|
||||
* @note This structure content is architecture dependent, each driver
|
||||
* implementation defines its own version and the custom static
|
||||
* initializers.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Bit rate.
|
||||
*/
|
||||
uint32_t speed;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Initialization value for the CR register.
|
||||
*/
|
||||
uint32_t cr;
|
||||
/**
|
||||
* @brief Initialization value for the MR register.
|
||||
*/
|
||||
uint32_t mr;
|
||||
} SerialConfig;
|
||||
|
||||
/**
|
||||
* @brief @p SerialDriver specific data.
|
||||
*/
|
||||
#define _serial_driver_data \
|
||||
_base_asynchronous_channel_data \
|
||||
/* Driver state.*/ \
|
||||
sdstate_t state; \
|
||||
/* Input queue.*/ \
|
||||
input_queue_t iqueue; \
|
||||
/* Output queue.*/ \
|
||||
output_queue_t oqueue; \
|
||||
/* End of the mandatory fields.*/ \
|
||||
/* Pointer to the UART registers block.*/ \
|
||||
Uart *uart; \
|
||||
/* Pointer to the FLEXCOM registers block.*/ \
|
||||
Flexcom *flexcom; \
|
||||
/* Pointer to the UART registers block.*/ \
|
||||
Usart *usart; \
|
||||
/* Clock frequency for the associated USART/UART.*/ \
|
||||
uint32_t clock;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD0;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD1;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD2;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD3;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_UART4 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver SD4;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_FLEXCOM0 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver FSD0;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_FLEXCOM1 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver FSD1;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_FLEXCOM2 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver FSD2;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_FLEXCOM3 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver FSD3;
|
||||
#endif
|
||||
#if SAMA_SERIAL_USE_FLEXCOM4 && !defined(__DOXYGEN__)
|
||||
extern SerialDriver FSD4;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void sd_lld_init(void);
|
||||
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
|
||||
void sd_lld_stop(SerialDriver *sdp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_SERIAL */
|
||||
|
||||
#endif /* HAL_SERIAL_LLD_H */
|
||||
|
||||
/** @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,656 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file USARTv1/hal_uart_lld.h
|
||||
* @brief SAMA low level UART driver header.
|
||||
*
|
||||
* @addtogroup UART
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_UART_LLD_H
|
||||
#define HAL_UART_LLD_H
|
||||
|
||||
#if HAL_USE_UART || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief UART driver on UART0 enable switch.
|
||||
* @details If set to @p TRUE the support for UART0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_UART0) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_UART0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on UART1 enable switch.
|
||||
* @details If set to @p TRUE the support for UART1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_UART1) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_UART1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on UART2 enable switch.
|
||||
* @details If set to @p TRUE the support for UART2 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_UART2) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_UART2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on UART3 enable switch.
|
||||
* @details If set to @p TRUE the support for UART4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_UART3) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_UART3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on UART4 enable switch.
|
||||
* @details If set to @p TRUE the support for UART4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_UART4) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_UART4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on FLEXCOM0 enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_FLEXCOM0) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_FLEXCOM0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on FLEXCOM1 enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_FLEXCOM1) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_FLEXCOM1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on FLEXCOM2 enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM2 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_FLEXCOM2) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_FLEXCOM2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on FLEXCOM3 enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM3 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_FLEXCOM3) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_FLEXCOM3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART driver on FLEXCOM4 enable switch.
|
||||
* @details If set to @p TRUE the support for FLEXCOM4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SAMA_UART_USE_FLEXCOM4) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_USE_FLEXCOM4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART0_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART1_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART2_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART3_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART4_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM0_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM1_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM2 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM2_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM3 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM3_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM4 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM4_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART0 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART0_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART1 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART1_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART2 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART2_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART3 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART3_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART4 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_UART4_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_UART4_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM0 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM0_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM1 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM1_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM2 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM2_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM3 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM3_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FLEXCOM4 DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_UART_FLEXCOM4_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_FLEXCOM4_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART DMA error hook.
|
||||
* @note The default action for DMA errors is a system halt because DMA
|
||||
* error can only happen because programming errors.
|
||||
*/
|
||||
#if !defined(SAMA_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UART cache managing.
|
||||
*/
|
||||
#if !defined(SAMA_UART_CACHE_USER_MANAGED) || defined(__DOXYGEN__)
|
||||
#define SAMA_UART_CACHE_USER_MANAGED FALSE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief At least an UART unit is in use.
|
||||
*/
|
||||
#define SAMA_UART_USE_UART (SAMA_UART_USE_UART0 || \
|
||||
SAMA_UART_USE_UART1 || \
|
||||
SAMA_UART_USE_UART2 || \
|
||||
SAMA_UART_USE_UART3 || \
|
||||
SAMA_UART_USE_UART4)
|
||||
|
||||
/**
|
||||
* @brief At least an FLEXCOM unit is in use.
|
||||
*/
|
||||
#define SAMA_UART_USE_FLEXCOM (SAMA_UART_USE_FLEXCOM0 || \
|
||||
SAMA_UART_USE_FLEXCOM1 || \
|
||||
SAMA_UART_USE_FLEXCOM2 || \
|
||||
SAMA_UART_USE_FLEXCOM3 || \
|
||||
SAMA_UART_USE_FLEXCOM4)
|
||||
|
||||
|
||||
#if !SAMA_UART_USE_UART0 && !SAMA_UART_USE_UART1 && \
|
||||
!SAMA_UART_USE_UART2 && !SAMA_UART_USE_UART3 && \
|
||||
!SAMA_UART_USE_UART4 && \
|
||||
!SAMA_UART_USE_FLEXCOM0 && !SAMA_UART_USE_FLEXCOM1 && \
|
||||
!SAMA_UART_USE_FLEXCOM2 && !SAMA_UART_USE_FLEXCOM3 && \
|
||||
!SAMA_UART_USE_FLEXCOM4
|
||||
#error "UART driver activated but no USART/UART peripheral assigned"
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of UARTx units.*/
|
||||
#if SAMA_UART_USE_UART0
|
||||
#if defined(SAMA_UART0_IS_USED)
|
||||
#error "UARTD0 requires UART0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART1
|
||||
#if defined(SAMA_UART1_IS_USED)
|
||||
#error "UARTD1 requires UART1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART2
|
||||
#if defined(SAMA_UART2_IS_USED)
|
||||
#error "UARTD2 requires UART2 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART2_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART3
|
||||
#if defined(SAMA_UART3_IS_USED)
|
||||
#error "UARTD3 requires UART3 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART3_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART4
|
||||
#if defined(SAMA_UART4_IS_USED)
|
||||
#error "UARTD4 requires UART4 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_UART4_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM0
|
||||
#if defined(SAMA_FLEXCOM0_IS_USED)
|
||||
#error "FUARTD0 requires FLEXCOM0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM1
|
||||
#if defined(SAMA_FLEXCOM1_IS_USED)
|
||||
#error "FUARTD1 requires FLEXCOM1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM2
|
||||
#if defined(SAMA_FLEXCOM2_IS_USED)
|
||||
#error "FUARTD2 requires FLEXCOM2 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM2_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM3
|
||||
#if defined(SAMA_FLEXCOM3_IS_USED)
|
||||
#error "FUARTD3 requires FLEXCOM3 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM3_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM4
|
||||
#if defined(SAMA_FLEXCOM4_IS_USED)
|
||||
#error "FUARTD4 requires FLEXCOM4 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_FLEXCOM4_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA_DMA_REQUIRED)
|
||||
#define SAMA_DMA_REQUIRED
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief UART driver condition flags type.
|
||||
*/
|
||||
typedef uint32_t uartflags_t;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an UART driver.
|
||||
*/
|
||||
typedef struct UARTDriver UARTDriver;
|
||||
|
||||
/**
|
||||
* @brief Generic UART notification callback type.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
typedef void (*uartcb_t)(UARTDriver *uartp);
|
||||
|
||||
/**
|
||||
* @brief Character received UART notification callback type.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
* @param[in] c received character
|
||||
*/
|
||||
typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c);
|
||||
|
||||
/**
|
||||
* @brief Receive error UART notification callback type.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
* @param[in] e receive error mask
|
||||
*/
|
||||
typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief End of transmission buffer callback.
|
||||
*/
|
||||
uartcb_t txend1_cb;
|
||||
/**
|
||||
* @brief Physical end of transmission callback.
|
||||
*/
|
||||
uartcb_t txend2_cb;
|
||||
/**
|
||||
* @brief Receive buffer filled callback.
|
||||
*/
|
||||
uartcb_t rxend_cb;
|
||||
/**
|
||||
* @brief Character received while out if the @p UART_RECEIVE state.
|
||||
*/
|
||||
uartccb_t rxchar_cb;
|
||||
/**
|
||||
* @brief Receive error callback.
|
||||
*/
|
||||
uartecb_t rxerr_cb;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Receiver timeout callback.
|
||||
* @details Handles both idle and timeout interrupts depending on configured
|
||||
* flags in CR registers and supported hardware features.
|
||||
*/
|
||||
uartcb_t timeout_cb;
|
||||
/**
|
||||
* @brief Receiver timeout value in terms of number of bit duration.
|
||||
* @details Set it to 0 when you want to handle idle interrupt instead of
|
||||
* hardware timeout.
|
||||
*/
|
||||
uint32_t timeout;
|
||||
/**
|
||||
* @brief Bit rate.
|
||||
*/
|
||||
uint32_t speed;
|
||||
/**
|
||||
* @brief Initialization value for the CR register.
|
||||
*/
|
||||
uint32_t cr;
|
||||
/**
|
||||
* @brief Initialization value for the MR register.
|
||||
*/
|
||||
uint32_t mr;
|
||||
} UARTConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an UART driver.
|
||||
*/
|
||||
struct UARTDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
uartstate_t state;
|
||||
/**
|
||||
* @brief Transmitter state.
|
||||
*/
|
||||
uarttxstate_t txstate;
|
||||
/**
|
||||
* @brief Receiver state.
|
||||
*/
|
||||
uartrxstate_t rxstate;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const UARTConfig *config;
|
||||
#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Synchronization flag for transmit operations.
|
||||
*/
|
||||
bool early;
|
||||
/**
|
||||
* @brief Waiting thread on RX.
|
||||
*/
|
||||
thread_reference_t threadrx;
|
||||
/**
|
||||
* @brief Waiting thread on TX.
|
||||
*/
|
||||
thread_reference_t threadtx;
|
||||
#endif /* UART_USE_WAIT */
|
||||
#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the peripheral.
|
||||
*/
|
||||
mutex_t mutex;
|
||||
#endif /* UART_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(UART_DRIVER_EXT_FIELDS)
|
||||
UART_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
#if SAMA_UART_USE_UART
|
||||
/**
|
||||
* @brief Pointer to the UART registers block.
|
||||
*/
|
||||
Uart *uart;
|
||||
#endif
|
||||
#if SAMA_UART_USE_FLEXCOM
|
||||
/* Pointer to the FLEXCOM registers block.*/
|
||||
Flexcom *flexcom;
|
||||
/* Pointer to the USART registers block.*/
|
||||
Usart *usart;
|
||||
#endif
|
||||
/**
|
||||
* @brief Clock frequency for the associated USART/UART.
|
||||
*/
|
||||
uint32_t clock;
|
||||
/**
|
||||
* @brief DMA mode bit mask.
|
||||
*/
|
||||
uint32_t rxdmamode;
|
||||
/**
|
||||
* @brief DMA mode bit mask.
|
||||
*/
|
||||
uint32_t txdmamode;
|
||||
/**
|
||||
* @brief Receive DMA channel.
|
||||
*/
|
||||
sama_dma_channel_t *dmarx;
|
||||
/**
|
||||
* @brief Transmit DMA channel.
|
||||
*/
|
||||
sama_dma_channel_t *dmatx;
|
||||
/**
|
||||
* @brief Default receive buffer while into @p UART_RX_IDLE state.
|
||||
*/
|
||||
CACHE_ALIGNED
|
||||
volatile uint16_t rxbuf;
|
||||
/**
|
||||
* @brief Pointer to the TX buffer location.
|
||||
*/
|
||||
const uint8_t *txbufp;
|
||||
/**
|
||||
* @brief Pointer to the RX buffer location.
|
||||
*/
|
||||
uint8_t *rxbufp;
|
||||
/**
|
||||
* @brief Number of bytes in RX phase.
|
||||
*/
|
||||
size_t rxbytes;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_UART_USE_UART0 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver UARTD0;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART1 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver UARTD1;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART2 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver UARTD2;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART3 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver UARTD3;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_UART4 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver UARTD4;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM0 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver FUARTD0;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM1 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver FUARTD1;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM2 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver FUARTD2;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM3 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver FUARTD3;
|
||||
#endif
|
||||
|
||||
#if SAMA_UART_USE_FLEXCOM4 && !defined(__DOXYGEN__)
|
||||
extern UARTDriver FUARTD4;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void uart_lld_init(void);
|
||||
void uart_lld_start(UARTDriver *uartp);
|
||||
void uart_lld_stop(UARTDriver *uartp);
|
||||
void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf);
|
||||
size_t uart_lld_stop_send(UARTDriver *uartp);
|
||||
void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf);
|
||||
size_t uart_lld_stop_receive(UARTDriver *uartp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_UART */
|
||||
|
||||
#endif /* HAL_UART_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,9 +0,0 @@
|
|||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
ifneq ($(findstring HAL_USE_WDG TRUE,$(HALCONF)),)
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c
|
||||
endif
|
||||
else
|
||||
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c
|
||||
endif
|
||||
|
||||
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file WDGv1/hal_wdg_lld.c
|
||||
* @brief WDG Driver subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup WDG
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief WDG driver identifier.
|
||||
*/
|
||||
WDGDriver WDGD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Local function that computes the period
|
||||
* for WDT_MR_WDV and WDT_MR_VDD registers.
|
||||
*
|
||||
* @param[in] period period to be computed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static uint32_t wdt_compute_period(uint32_t period) {
|
||||
|
||||
uint32_t value;
|
||||
value = period * (SAMA_SLOW_CLK >> 7) / 1000;
|
||||
if (value > 0xfff)
|
||||
value = 0xfff;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief WDG IRQ handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_WDG_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
/* Read status register. */
|
||||
uint32_t sr = WDT->WDT_SR;
|
||||
|
||||
if (WDGD0.config->callback != NULL) {
|
||||
if (sr & WDT_SR_WDERR) {
|
||||
WDGD0.config->callback(&WDGD0, WDG_ERROR);
|
||||
}
|
||||
|
||||
else
|
||||
WDGD0.config->callback(&WDGD0, WDG_UNDERFLOW);
|
||||
}
|
||||
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level WDG driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void wdg_lld_init(void) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_WDT, SECURE_PER);
|
||||
#endif
|
||||
|
||||
WDGD0.state = WDG_STOP;
|
||||
WDGD0.wdg = WDT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the WDT peripheral.
|
||||
*
|
||||
* @param[in] wdgp pointer to the @p WDGDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void wdg_lld_start(WDGDriver *wdgp) {
|
||||
|
||||
(void) wdgp;
|
||||
|
||||
/* Read status register. */
|
||||
WDT->WDT_SR;
|
||||
|
||||
/* Write configuration */
|
||||
WDT->WDT_MR = (wdgp->config->mode & ~(WDT_MR_WDDIS | WDT_MR_WDD_Msk | WDT_MR_WDV_Msk)) |
|
||||
WDT_MR_WDV(wdt_compute_period(wdgp->config->counter)) |
|
||||
WDT_MR_WDD(wdt_compute_period(wdgp->config->delta));
|
||||
|
||||
aicSetSourcePriority(ID_WDT, SAMA_WDG_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_WDT, SAMA_WDG_HANDLER);
|
||||
aicEnableInt(ID_WDT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the WDG peripheral.
|
||||
*
|
||||
* @param[in] wdgp pointer to the @p WDGDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void wdg_lld_stop(WDGDriver *wdgp) {
|
||||
|
||||
(void) wdgp;
|
||||
WDT->WDT_MR = WDT_MR_WDDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reloads the WDG counter.
|
||||
*
|
||||
* @param[in] wdgp pointer to the @p WDGDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void wdg_lld_reset(WDGDriver * wdgp) {
|
||||
|
||||
(void) wdgp;
|
||||
WDT->WDT_CR = WDT_CR_KEY_PASSWD | WDT_CR_WDRSTT;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_WDG == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file WDGv1/hal_wdg_lld.h
|
||||
* @brief WDG Driver subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup WDG
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_WDG_LLD_H
|
||||
#define HAL_WDG_LLD_H
|
||||
|
||||
#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/*
|
||||
* WDG driver system settings.
|
||||
*/
|
||||
#define SAMA_WDG_IRQ_PRIORITY 4
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Type of an WDG event.
|
||||
*/
|
||||
typedef enum {
|
||||
WDG_ERROR = 0, /** Watchdog fault error. */
|
||||
WDG_UNDERFLOW = 1 /** Watchdog underflow error. */
|
||||
} wdgevent_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an WDG driver.
|
||||
*/
|
||||
typedef struct WDGDriver WDGDriver;
|
||||
|
||||
/**
|
||||
* @brief Type of a generic WDG callback.
|
||||
*/
|
||||
typedef void (*wdgcb_t)(WDGDriver *wdgp, wdgevent_t event);
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Callback pointer.
|
||||
*/
|
||||
wdgcb_t callback;
|
||||
/**
|
||||
* @brief Configuration of the WDT modes.
|
||||
*/
|
||||
uint32_t mode;
|
||||
/**
|
||||
* @brief Configuration of the WDT counter.
|
||||
*/
|
||||
uint32_t counter;
|
||||
/**
|
||||
* @brief Configuration of the WDT delta.
|
||||
*/
|
||||
uint32_t delta;
|
||||
} WDGConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an WDG driver.
|
||||
*/
|
||||
struct WDGDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
wdgstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const WDGConfig *config;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the WDT registers block.
|
||||
*/
|
||||
Wdt *wdg;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern WDGDriver WDGD0;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void wdg_lld_init(void);
|
||||
void wdg_lld_start(WDGDriver *wdgp);
|
||||
void wdg_lld_stop(WDGDriver *wdgp);
|
||||
void wdg_lld_reset(WDGDriver *wdgp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_WDG == TRUE */
|
||||
|
||||
#endif /* HAL_WDG_LLD_H */
|
||||
|
||||
/** @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,448 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_crypto_lld.h
|
||||
* @brief PLATFORM cryptographic subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup CRYPTO
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_CRYPTO_LLD_H
|
||||
#define HAL_CRYPTO_LLD_H
|
||||
|
||||
#if (HAL_USE_CRY == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Driver capability switches
|
||||
* @{
|
||||
*/
|
||||
#define CRY_LLD_SUPPORTS_AES TRUE
|
||||
#define CRY_LLD_SUPPORTS_AES_ECB TRUE
|
||||
#define CRY_LLD_SUPPORTS_AES_CBC TRUE
|
||||
#define CRY_LLD_SUPPORTS_AES_CFB TRUE
|
||||
#define CRY_LLD_SUPPORTS_AES_CTR TRUE
|
||||
#define CRY_LLD_SUPPORTS_AES_GCM TRUE
|
||||
#define CRY_LLD_SUPPORTS_DES TRUE
|
||||
#define CRY_LLD_SUPPORTS_DES_ECB TRUE
|
||||
#define CRY_LLD_SUPPORTS_DES_CBC TRUE
|
||||
#define CRY_LLD_SUPPORTS_SHA1 TRUE
|
||||
#define CRY_LLD_SUPPORTS_SHA256 TRUE
|
||||
#define CRY_LLD_SUPPORTS_SHA512 TRUE
|
||||
#define CRY_LLD_SUPPORTS_HMAC_SHA256 TRUE
|
||||
#define CRY_LLD_SUPPORTS_HMAC_SHA512 TRUE
|
||||
#define CRY_LLD_SUPPORTS_TRNG TRUE
|
||||
/** @{ */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name PLATFORM configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief CRY1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for CRY1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(PLATFORM_CRY_USE_CRY1) || defined(__DOXYGEN__)
|
||||
#define PLATFORM_CRY_USE_CRY1 FALSE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t encrypt;
|
||||
uint32_t block_size;
|
||||
uint32_t mode;
|
||||
const uint8_t *iv;
|
||||
}aesparams;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
aesparams params;
|
||||
|
||||
|
||||
size_t aadsize;
|
||||
size_t c_size;
|
||||
uint8_t *in;
|
||||
uint8_t *out;
|
||||
|
||||
uint8_t * aad;
|
||||
uint8_t *authtag;
|
||||
|
||||
}cgmcontext;
|
||||
|
||||
typedef enum {
|
||||
TRANSFER_DMA = 0,
|
||||
TRANSFER_POLLING,
|
||||
}crytransfermode_t;
|
||||
|
||||
typedef enum {
|
||||
AES_CFBS_128 = 0,
|
||||
AES_CFBS_64,
|
||||
AES_CFBS_32,
|
||||
AES_CFBS_16,
|
||||
AES_CFBS_8
|
||||
}aesciphersize_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
CRY_SHA_1,
|
||||
CRY_SHA_224,
|
||||
CRY_SHA_256,
|
||||
CRY_SHA_384,
|
||||
CRY_SHA_512,
|
||||
|
||||
CRY_HMACSHA_1,
|
||||
CRY_HMACSHA_224,
|
||||
CRY_HMACSHA_256,
|
||||
CRY_HMACSHA_384,
|
||||
CRY_HMACSHA_512,
|
||||
|
||||
}shadalgo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
shadalgo_t algo;
|
||||
}shaparams_t;
|
||||
|
||||
/**
|
||||
* @brief CRY key identifier type.
|
||||
*/
|
||||
typedef uint32_t crykey_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an CRY driver.
|
||||
*/
|
||||
typedef struct CRYDriver CRYDriver;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
TDES_ALGO_SINGLE = 0,
|
||||
TDES_ALGO_TRIPLE,
|
||||
TDES_ALGO_XTEA
|
||||
}tdes_algo_t;
|
||||
|
||||
struct sha_data {
|
||||
uint32_t remaining;
|
||||
uint32_t processed;
|
||||
uint32_t block_size;
|
||||
uint32_t output_size;
|
||||
uint32_t sha_buffer_size;
|
||||
const uint8_t *in;
|
||||
uint8_t *out;
|
||||
size_t indata_len;
|
||||
uint8_t *sha_buffer;
|
||||
|
||||
shadalgo_t algo;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
crytransfermode_t transfer_mode;
|
||||
uint32_t cfbs;
|
||||
} CRYConfig;
|
||||
|
||||
#define KEY0_BUFFER_SIZE_W HAL_CRY_MAX_KEY_SIZE/4
|
||||
|
||||
|
||||
#define CRY_DRIVER_EXT_FIELDS thread_reference_t thread; \
|
||||
sama_dma_channel_t *dmarx; \
|
||||
sama_dma_channel_t *dmatx; \
|
||||
uint32_t rxdmamode; \
|
||||
uint32_t txdmamode; \
|
||||
uint8_t dmawith; \
|
||||
uint8_t dmachunksize; \
|
||||
uint8_t enabledPer; \
|
||||
mutex_t mutex; \
|
||||
uint32_t key0_buffer[KEY0_BUFFER_SIZE_W];
|
||||
|
||||
/**
|
||||
* @brief Structure representing an CRY driver.
|
||||
*/
|
||||
struct CRYDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
crystate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const CRYConfig *config;
|
||||
/**
|
||||
* @brief Algorithm type of transient key.
|
||||
*/
|
||||
cryalgorithm_t key0_type;
|
||||
/**
|
||||
* @brief Size of transient key.
|
||||
*/
|
||||
size_t key0_size;
|
||||
/**
|
||||
* @brief Pointer to the in buffer location.
|
||||
*/
|
||||
const uint8_t *in;
|
||||
/**
|
||||
* @brief Pointer to the out buffer location.
|
||||
*/
|
||||
uint8_t *out;
|
||||
/**
|
||||
* @brief Number of bytes.
|
||||
*/
|
||||
size_t len;
|
||||
#if (HAL_CRY_USE_FALLBACK == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Key buffer for the fall-back implementation.
|
||||
*/
|
||||
uint8_t key0_buffer[HAL_CRY_MAX_KEY_SIZE];
|
||||
#endif
|
||||
#if defined(CRY_DRIVER_EXT_FIELDS)
|
||||
CRY_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
};
|
||||
|
||||
#if (CRY_LLD_SUPPORTS_SHA1 == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a SHA1 context.
|
||||
*/
|
||||
typedef struct {
|
||||
struct sha_data sha;
|
||||
} SHA1Context;
|
||||
#endif
|
||||
|
||||
#if (CRY_LLD_SUPPORTS_SHA256 == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a SHA256 context.
|
||||
*/
|
||||
typedef struct {
|
||||
struct sha_data sha;
|
||||
} SHA256Context;
|
||||
#endif
|
||||
|
||||
#if (CRY_LLD_SUPPORTS_SHA512 == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a SHA512 context.
|
||||
*/
|
||||
typedef struct {
|
||||
struct sha_data sha;
|
||||
} SHA512Context;
|
||||
#endif
|
||||
#if (CRY_LLD_SUPPORTS_HMAC_SHA256 == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a HMAC_SHA256 context.
|
||||
*/
|
||||
typedef struct {
|
||||
SHA256Context shacontext;
|
||||
uint8_t kipad;
|
||||
} HMACSHA256Context;
|
||||
#endif
|
||||
|
||||
#if (CRY_LLD_SUPPORTS_HMAC_SHA512 == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a HMAC_SHA512 context.
|
||||
*/
|
||||
typedef struct {
|
||||
SHA512Context shacontext;
|
||||
uint8_t kipad;
|
||||
} HMACSHA512Context;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (PLATFORM_CRY_USE_CRY1 == TRUE) && !defined(__DOXYGEN__)
|
||||
extern CRYDriver CRYD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void cry_lld_init(void);
|
||||
void cry_lld_start(CRYDriver *cryp);
|
||||
void cry_lld_stop(CRYDriver *cryp);
|
||||
cryerror_t cry_lld_loadkey(CRYDriver *cryp,
|
||||
cryalgorithm_t algorithm,
|
||||
size_t size,
|
||||
const uint8_t *keyp);
|
||||
cryerror_t cry_lld_encrypt_AES(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_decrypt_AES(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_encrypt_AES_ECB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_decrypt_AES_ECB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_encrypt_AES_CBC(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_decrypt_AES_CBC(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_encrypt_AES_CFB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_decrypt_AES_CFB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_encrypt_AES_CTR(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_decrypt_AES_CTR(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_encrypt_AES_GCM(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv,
|
||||
size_t aadsize,
|
||||
const uint8_t *aad,
|
||||
uint8_t *authtag);
|
||||
cryerror_t cry_lld_decrypt_AES_GCM(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv,
|
||||
size_t aadsize,
|
||||
const uint8_t *aad,
|
||||
uint8_t *authtag);
|
||||
cryerror_t cry_lld_encrypt_DES(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_decrypt_DES(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_encrypt_DES_ECB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_decrypt_DES_ECB(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_encrypt_DES_CBC(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_decrypt_DES_CBC(CRYDriver *cryp,
|
||||
crykey_t key_id,
|
||||
size_t size,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
const uint8_t *iv);
|
||||
cryerror_t cry_lld_SHA1_init(CRYDriver *cryp, SHA1Context *sha1ctxp);
|
||||
cryerror_t cry_lld_SHA1_update(CRYDriver *cryp, SHA1Context *sha1ctxp,
|
||||
size_t size, const uint8_t *in);
|
||||
cryerror_t cry_lld_SHA1_final(CRYDriver *cryp, SHA1Context *sha1ctxp,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_SHA256_init(CRYDriver *cryp, SHA256Context *sha256ctxp);
|
||||
cryerror_t cry_lld_SHA256_update(CRYDriver *cryp, SHA256Context *sha256ctxp,
|
||||
size_t size, const uint8_t *in);
|
||||
cryerror_t cry_lld_SHA256_final(CRYDriver *cryp, SHA256Context *sha256ctxp,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_SHA512_init(CRYDriver *cryp, SHA512Context *sha512ctxp);
|
||||
cryerror_t cry_lld_SHA512_update(CRYDriver *cryp, SHA512Context *sha512ctxp,
|
||||
size_t size, const uint8_t *in);
|
||||
cryerror_t cry_lld_SHA512_final(CRYDriver *cryp, SHA512Context *sha512ctxp,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_HMACSHA256_init(CRYDriver *cryp,
|
||||
HMACSHA256Context *hmacsha256ctxp);
|
||||
cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp,
|
||||
HMACSHA256Context *hmacsha256ctxp,
|
||||
size_t size, const uint8_t *in);
|
||||
cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp,
|
||||
HMACSHA256Context *hmacsha256ctxp,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_HMACSHA512_init(CRYDriver *cryp,
|
||||
HMACSHA512Context *hmacsha512ctxp);
|
||||
cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp,
|
||||
HMACSHA512Context *hmacsha512ctxp,
|
||||
size_t size, const uint8_t *in);
|
||||
cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp,
|
||||
HMACSHA512Context *hmacsha512ctxp,
|
||||
uint8_t *out);
|
||||
cryerror_t cry_lld_TRNG(CRYDriver *cryp, uint8_t *out);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_CRY == TRUE */
|
||||
|
||||
#endif /* HAL_CRYPTO_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_lld.c
|
||||
* @brief PLATFORM HAL subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup HAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define SAMA_MOR_ONE (1 << 5)
|
||||
#define SAMA_MOR_MOSCXTST CKGR_MOR_MOSCXTST(0xFF)
|
||||
|
||||
#define SAMA_PLLA_ONE (1 << 29)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level HAL driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void hal_lld_init(void) {
|
||||
|
||||
#if (SAMA_HAL_IS_SECURE == TRUE) /* The Matrix is PAS and PMC is always configured secure */
|
||||
/* Disabling PMC write protection. */
|
||||
pmcDisableWP();
|
||||
|
||||
PIT->PIT_MR &= ~(PIT_MR_PITEN | PIT_MR_PITIEN);
|
||||
|
||||
/* Configures peripherals as not-secure */
|
||||
MATRIX0->MATRIX_SPSELR[0] = 0xFFFFFFFF;
|
||||
MATRIX0->MATRIX_SPSELR[1] = 0xFFFFFFFF;
|
||||
MATRIX0->MATRIX_SPSELR[2] = 0xFFFFFFFF;
|
||||
MATRIX1->MATRIX_SPSELR[0] = 0xFFFFFFFF;
|
||||
MATRIX1->MATRIX_SPSELR[1] = 0xFFFFFFFF;
|
||||
MATRIX1->MATRIX_SPSELR[2] = 0xFFFFFFFF;
|
||||
|
||||
/* Configures PMC and RTC as secure */
|
||||
//mtxConfigPeriphSecurity(MATRIX1, ID_SYSC, SECURE_PER);
|
||||
mtxConfigPeriphSecurity(MATRIX0, ID_PMC, SECURE_PER);
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SFC, SECURE_PER);
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SFR, SECURE_PER);
|
||||
|
||||
/* It isn't necessary to make L2CC secure. L2C-310 cache
|
||||
* controller is secure mode aware.*/
|
||||
/*mtxConfigPeriphSecurity(MATRIX0, ID_L2CC, SECURE_PER);*/
|
||||
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_SFRBU, SECURE_PER);
|
||||
/*mtxConfigPeriphSecurity(MATRIX1, ID_CHIPID, SECURE_PER);*/
|
||||
|
||||
/* Enabling matrix clock */
|
||||
pmcEnableH32MX();
|
||||
pmcEnableH64MX();
|
||||
/* Enabling write protection. */
|
||||
pmcEnableWP();
|
||||
#endif
|
||||
|
||||
/* Advanced interrupt controller init */
|
||||
aicInit();
|
||||
|
||||
#if defined(SAMA_DMA_REQUIRED)
|
||||
dmaInit();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SAMA clocks and PLL initialization.
|
||||
* @note All the involved constants come from the file @p board.h.
|
||||
* @note This function should be invoked just after the system reset.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void sama_clock_init(void) {
|
||||
#if (!SAMA_NO_INIT && SAMA_HAL_IS_SECURE == TRUE)
|
||||
uint32_t mor, pllar, mckr, mainf;
|
||||
/* Disabling PMC write protection. */
|
||||
pmcDisableWP();
|
||||
|
||||
/*
|
||||
* Enforcing the reset default configuration of clock tree.
|
||||
*/
|
||||
/* Setting Slow Clock source to OSCRC. */
|
||||
SCKC->SCKC_CR = 0U;
|
||||
|
||||
/* Enabling MOSCRC. */
|
||||
PMC->CKGR_MOR |= (CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN);
|
||||
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS))
|
||||
; /* Waits until MOSCRC is stable.*/
|
||||
|
||||
/* Switching Main Oscillator Source to MOSRC. */
|
||||
mor = PMC->CKGR_MOR | CKGR_MOR_KEY_PASSWD;
|
||||
mor &= ~CKGR_MOR_MOSCSEL;
|
||||
mor |= SAMA_MOSC_MOSCRC;
|
||||
PMC->CKGR_MOR = mor;
|
||||
|
||||
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS))
|
||||
; /* Waits until MOSCSEL has changed.*/
|
||||
|
||||
/* Switching Master Clock source to Main Clock. */
|
||||
mckr = PMC->PMC_MCKR;
|
||||
mckr &= ~PMC_MCKR_CSS_Msk;
|
||||
mckr |= PMC_MCKR_CSS_MAIN_CLK;
|
||||
PMC->PMC_MCKR = mckr;
|
||||
|
||||
while (!(PMC->PMC_SR & PMC_SR_MCKRDY))
|
||||
; /* Waits until Master Clock is stable.*/
|
||||
|
||||
/* Counter Clock Source to MOSCRC. */
|
||||
PMC->CKGR_MCFR &= ~CKGR_MCFR_CCSS;
|
||||
|
||||
|
||||
/*
|
||||
* Main oscillator configuration block.
|
||||
*/
|
||||
/* Setting Slow clock source. */
|
||||
SCKC->SCKC_CR = SAMA_OSC_SEL;
|
||||
while ((SAMA_OSC_SEL && !(PMC->PMC_SR & PMC_SR_OSCSELS)) ||
|
||||
(!SAMA_OSC_SEL && (PMC->PMC_SR & PMC_SR_OSCSELS)))
|
||||
; /* Waits until MOSCxxS switch is done.*/
|
||||
mor = PMC->CKGR_MOR | CKGR_MOR_KEY_PASSWD;
|
||||
#if SAMA_MOSCXT_ENABLED
|
||||
mor |= CKGR_MOR_MOSCXTEN;
|
||||
PMC->CKGR_MOR = mor;
|
||||
while (!(PMC->PMC_SR & PMC_SR_MOSCXTS))
|
||||
; /* Waits until MOSCXT is stable.*/
|
||||
/* Counter Clock Source to MOSCXT. */
|
||||
PMC->CKGR_MCFR |= CKGR_MCFR_CCSS;
|
||||
#else
|
||||
mor &= ~CKGR_MOR_MOSCXTEN;
|
||||
PMC->CKGR_MOR = mor;
|
||||
#endif
|
||||
|
||||
PMC->CKGR_MCFR |= CKGR_MCFR_RCMEAS;
|
||||
while (!(PMC->CKGR_MCFR & CKGR_MCFR_MAINFRDY))
|
||||
;
|
||||
mainf = CKGR_MCFR_MAINF(PMC->CKGR_MCFR);
|
||||
/*
|
||||
* @TODO: add mainf check and eventual clock source fallback. This mechanism
|
||||
* should be activable through a switch.
|
||||
*/
|
||||
(void)mainf;
|
||||
|
||||
/* Switching Main Clock source. */
|
||||
mor &= ~CKGR_MOR_MOSCSEL;
|
||||
mor |= SAMA_MOSC_SEL;
|
||||
PMC->CKGR_MOR = mor;
|
||||
|
||||
/* Eventually disabling MOSCRC. */
|
||||
#if !SAMA_MOSCRC_ENABLED
|
||||
PMC->CKGR_MOR &= ~ CKGR_MOR_MOSCRCEN;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PLLA configuration block.
|
||||
*/
|
||||
pllar = SAMA_PLLA_ONE | CKGR_PLLAR_PLLACOUNT(0x3F);
|
||||
#if SAMA_ACTIVATE_PLLA
|
||||
pllar |= CKGR_PLLAR_DIVA_BYPASS | SAMA_PLLA_MUL;
|
||||
#endif
|
||||
PMC->CKGR_PLLAR = pllar; /* Writing PLLA register. */
|
||||
|
||||
#if SAMA_ACTIVATE_PLLA
|
||||
while (!(PMC->PMC_SR & PMC_SR_LOCKA))
|
||||
; /* Waits until PLLA is locked. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Master clock configuration block.
|
||||
*/
|
||||
mckr = PMC->PMC_MCKR;
|
||||
mckr &= ~PMC_MCKR_CSS_Msk;
|
||||
mckr |= SAMA_MCK_SEL;
|
||||
PMC->PMC_MCKR = mckr;
|
||||
while (!(PMC->PMC_SR & PMC_SR_MCKRDY))
|
||||
; /* Waits until MCK is stable. */
|
||||
|
||||
mckr &= ~(PMC_MCKR_PRES_Msk | PMC_MCKR_MDIV_Msk | PMC_MCKR_H32MXDIV);
|
||||
|
||||
/* Note that prescaler and divider must be changed with separate accesses.*/
|
||||
mckr |= SAMA_MCK_PRES;
|
||||
mckr |= SAMA_MCK_MDIV;
|
||||
mckr |= SAMA_H64MX_H32MX_DIV;
|
||||
#if SAMA_PLLADIV2_EN
|
||||
mckr |= PMC_MCKR_PLLADIV2;
|
||||
#else
|
||||
mckr &= ~PMC_MCKR_PLLADIV2;
|
||||
#endif
|
||||
PMC->PMC_MCKR = mckr;
|
||||
while (!(PMC->PMC_SR & PMC_SR_MCKRDY))
|
||||
; /* Waits until MCK is stable. */
|
||||
|
||||
/* Enabling write protection. */
|
||||
pmcEnableWP();
|
||||
|
||||
#endif /* !SAMA_NO_INIT */
|
||||
}
|
||||
/** @} */
|
|
@ -1,545 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/hal_lld.h
|
||||
* @brief SAMA5D2x HAL subsystem low level driver header.
|
||||
* @pre This module requires the following macros to be defined in the
|
||||
* @p board.h file:
|
||||
* - SAMA_MOSCXTCLK.
|
||||
* - SAMA_OSCXTCLK
|
||||
* .
|
||||
* One of the following macros must also be defined:
|
||||
* - SAMA5D21, SAMA5D22, SAMA5D23, SAMA5D24, SAMA5D25, SAMA5D26,
|
||||
* SAMA5D27, SAMA5D28.
|
||||
*
|
||||
* @addtogroup HAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _HAL_LLD_H_
|
||||
#define _HAL_LLD_H_
|
||||
|
||||
#include "sama_registry.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Platform identification macros
|
||||
* @{
|
||||
*/
|
||||
#if defined(SAMA5D21) || defined(__DOXYGEN__)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16-bit DDR, BGA196"
|
||||
|
||||
#elif defined(SAMA5D22)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16-bit DDR, CAN, BGA196"
|
||||
|
||||
#elif defined(SAMA5D23)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16-bit DDR, CAN, Enhanced Security, BGA196"
|
||||
|
||||
#elif defined(SAMA5D24)
|
||||
#define PLATFORM_NAME "A500Mhz processor with TrustZone, 16/32-bit DDR, USB HSIC, BGA256"
|
||||
|
||||
#elif defined(SAMA5D25)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16/32-bit DDR, BGA289"
|
||||
|
||||
#elif defined(SAMA5D26)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16/32-bit DDR, CAN, BGA289"
|
||||
|
||||
#elif defined(SAMA5D27)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16/32-bit DDR, CAN, Enhanced Security, BGA289"
|
||||
|
||||
#elif defined(SAMA5D28)
|
||||
#define PLATFORM_NAME "500Mhz processor with TrustZone, 16/32-bit DDR, CAN, Enhanced Security, BGA289, 'internal DDR"
|
||||
|
||||
#else
|
||||
#error "SAMA5D2x device unsupported or not specified"
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Absolute Maximum Ratings
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Maximum processor clock frequency.
|
||||
*/
|
||||
#define SAMA_PCK_MAX 504000000
|
||||
|
||||
/**
|
||||
* @brief Minimum processor clock frequency.
|
||||
*/
|
||||
#define SAMA_PCK_MIN 250000000
|
||||
|
||||
/**
|
||||
* @brief Maximum master clock frequency.
|
||||
*/
|
||||
#define SAMA_MCK_MAX 168000000
|
||||
|
||||
/**
|
||||
* @brief Minimum master clock frequency.
|
||||
*/
|
||||
#define SAMA_MCK_MIN 125000000
|
||||
|
||||
/**
|
||||
* @brief Maximum Main Crystal Oscillator clock frequency.
|
||||
*/
|
||||
#define SAMA_MOSCXTCLK_MAX 24000000
|
||||
|
||||
/**
|
||||
* @brief Minimum Main Crystal Oscillator clock frequency.
|
||||
*/
|
||||
#define SAMA_MOSCXTCLK_MIN 8000000
|
||||
|
||||
/**
|
||||
* @brief Maximum PLLs input clock frequency.
|
||||
*/
|
||||
#define SAMA_PLLIN_MAX 24000000
|
||||
|
||||
/**
|
||||
* @brief Minimum PLLs input clock frequency.
|
||||
*/
|
||||
#define SAMA_PLLIN_MIN 800000
|
||||
|
||||
/**
|
||||
* @brief Maximum PLL output clock frequency.
|
||||
*/
|
||||
#define SAMA_PLLOUT_MAX 1200000000
|
||||
|
||||
/**
|
||||
* @brief Minimum PLL output clock frequency.
|
||||
*/
|
||||
#define SAMA_PLLOUT_MIN 600000000
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Internal clock sources
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_MOSCRCCLK 12000000 /**< RC Main oscillator clock. */
|
||||
#define SAMA_OSCRCCLK 32000 /**< RC Slow oscillator clock. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SCK_CR register bits definitions
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_OSC_OSCRC (0 << 3) /**< Slow Clock source MOSCRC. */
|
||||
#define SAMA_OSC_OSCXT (1 << 3) /**< Slow Clock source MOSCXT. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PCM_MOR register bits definitions
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_MOSC_MOSCRC (0 << 24) /**< Main Clock source MOSCRC. */
|
||||
#define SAMA_MOSC_MOSCXT (1 << 24) /**< Main Clock source MOSCXT. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PCM_MCR register bits definitions
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_MCK_SLOW_CLK (0 << 0) /**< MCK source is Slow Clock. */
|
||||
#define SAMA_MCK_MAIN_CLK (1 << 0) /**< MCK source is Main Clock. */
|
||||
#define SAMA_MCK_PLLA_CLK (2 << 0) /**< MCK source is PLLA Clock. */
|
||||
#define SAMA_MCK_UPLL_CLK (3 << 0) /**< MCK source is UPLL Clock. */
|
||||
|
||||
#define SAMA_MCK_PRE_DIV1 (0 << 4) /**< MCK not prescaled. */
|
||||
#define SAMA_MCK_PRE_DIV2 (1 << 4) /**< MCK prescaled by 2. */
|
||||
#define SAMA_MCK_PRE_DIV4 (2 << 4) /**< MCK prescaled by 4. */
|
||||
#define SAMA_MCK_PRE_DIV8 (3 << 4) /**< MCK prescaled by 8. */
|
||||
#define SAMA_MCK_PRE_DIV16 (4 << 4) /**< MCK prescaled by 16. */
|
||||
#define SAMA_MCK_PRE_DIV32 (5 << 4) /**< MCK prescaled by 32. */
|
||||
#define SAMA_MCK_PRE_DIV64 (6 << 4) /**< MCK prescaled by 64. */
|
||||
|
||||
#define SAMA_MCK_MDIV_DIV1 (0 << 8) /**< MCK is not divided. */
|
||||
#define SAMA_MCK_MDIV_DIV2 (1 << 8) /**< MCK is divided by 2. */
|
||||
#define SAMA_MCK_MDIV_DIV3 (3 << 8) /**< MCK is divided by 3. */
|
||||
#define SAMA_MCK_MDIV_DIV4 (2 << 8) /**< MCK is divided by 4. */
|
||||
|
||||
#define SAMA_MCK_PLLADIV2 (1 << 12) /**< PLLA is divided by 2. */
|
||||
|
||||
/**
|
||||
* @name PCM_PCR register bits definitions
|
||||
* @{
|
||||
*/
|
||||
#define SAMA_GCLK_SLOW_CLK (0x0u << 8) /**< GCLK Slow clock is selected */
|
||||
#define SAMA_GCLK_MAIN_CLK (0x1u << 8) /**< GCLK GMain clock is selected */
|
||||
#define SAMA_GCLK_PLLA_CLK (0x2u << 8) /**< GCLK PLLACK is selected */
|
||||
#define SAMA_GCLKUPLL_CLK (0x3u << 8) /**< GCLK UPLL Clock is selected */
|
||||
#define SAMA_GCLK_MCK_CLK (0x4u << 8) /**< GCLK Master Clock is selected */
|
||||
#define SAMA_GCLK_AUDIO_CLK (0x5u << 8) /**< GCLK Audio PLL clock is selected */
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Defines if the code is running in the secure side of the ARM Trust
|
||||
* Zone. It must be @p TRUE whenever the code is compiled for the
|
||||
* secure side.
|
||||
*/
|
||||
#if !defined(SAMA_HAL_IS_SECURE) || defined(__DOXYGEN__)
|
||||
#define SAMA_HAL_IS_SECURE TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Disables the PMC initialization in the HAL.
|
||||
*/
|
||||
#if !defined(SAMA_NO_INIT) || defined(__DOXYGEN__)
|
||||
#define SAMA_NO_INIT FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables or disables the MOSCRC clock source.
|
||||
*/
|
||||
#if !defined(SAMA_MOSCRC_ENABLED) || defined(__DOXYGEN__)
|
||||
#define SAMA_MOSCRC_ENABLED TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables or disables the MOSCXT clock source.
|
||||
*/
|
||||
#if !defined(SAMA_MOSCXT_ENABLED) || defined(__DOXYGEN__)
|
||||
#define SAMA_MOSCXT_ENABLED FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Main clock source selection.
|
||||
*/
|
||||
#if !defined(SAMA_MOSC_SEL) || defined(__DOXYGEN__)
|
||||
#define SAMA_MOSC_SEL SAMA_MOSC_MOSCRC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Slow clock source selection.
|
||||
*/
|
||||
#if !defined(SAMA_OSC_SEL) || defined(__DOXYGEN__)
|
||||
#define SAMA_OSC_SEL SAMA_OSC_OSCRC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master clock source selection.
|
||||
*/
|
||||
#if !defined(SAMA_MCK_SEL) || defined(__DOXYGEN__)
|
||||
#define SAMA_MCK_SEL SAMA_MCK_PLLA_CLK
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master clock prescaler.
|
||||
*/
|
||||
#if !defined(SAMA_MCK_PRES_VALUE) || defined(__DOXYGEN__)
|
||||
#define SAMA_MCK_PRES_VALUE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master clock divider.
|
||||
*/
|
||||
#if !defined(SAMA_MCK_MDIV_VALUE) || defined(__DOXYGEN__)
|
||||
#define SAMA_MCK_MDIV_VALUE 3
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLA clock multiplier.
|
||||
*/
|
||||
#if !defined(SAMA_PLLA_MUL_VALUE) || defined(__DOXYGEN__)
|
||||
#define SAMA_PLLA_MUL_VALUE 83
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLADIV2 clock divider.
|
||||
*/
|
||||
#if !defined(SAMA_PLLADIV2_EN) || defined(__DOXYGEN__)
|
||||
#define SAMA_PLLADIV2_EN TRUE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Configuration-related checks.
|
||||
*/
|
||||
#if !defined(SAMA5D2x_MCUCONF)
|
||||
#error "Using a wrong mcuconf.h file, SAMA5D2x_MCUCONF not defined"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Slow clock value.
|
||||
*/
|
||||
/* Main oscillator is fed by internal RC. */
|
||||
#if (SAMA_OSC_SEL == SAMA_OSC_OSCRC) || defined(__DOXYGEN__)
|
||||
#define SAMA_SLOW_CLK SAMA_OSCRCCLK
|
||||
#elif (SAMA_OSC_SEL == SAMA_OSC_OSCXT)
|
||||
#define SAMA_SLOW_CLK SAMA_OSCXTCLK
|
||||
#else
|
||||
#error "Wrong SAMA_OSC_SEL value."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MAIN clock value.
|
||||
*/
|
||||
/* Main oscillator is fed by internal RC. */
|
||||
#if (SAMA_MOSC_SEL == SAMA_MOSC_MOSCRC) || defined(__DOXYGEN__)
|
||||
#if !SAMA_MOSCRC_ENABLED
|
||||
#error "Internal RC oscillator disabled (required by SAMA_MOSC_SEL)."
|
||||
#endif
|
||||
#define SAMA_MAIN_CLK SAMA_MOSCRCCLK
|
||||
|
||||
/* Main oscillator is fed by external XTAL. */
|
||||
#elif (SAMA_MOSC_SEL == SAMA_MOSC_MOSCXT)
|
||||
#if !SAMA_MOSCXT_ENABLED
|
||||
#error "External crystal oscillator disabled (required by SAMA_MOSC_SEL)."
|
||||
#endif
|
||||
#define SAMA_MAIN_CLK SAMA_MOSCXTCLK
|
||||
/* Checks on external crystal range. */
|
||||
#if (SAMA_MOSCXTCLK > SAMA_MOSCXTCLK_MAX) || \
|
||||
(SAMA_MOSCXTCLK < SAMA_MOSCXTCLK_MIN)
|
||||
#error "External crystal oscillator out of range."
|
||||
#endif
|
||||
|
||||
/* Unallowed condition. */
|
||||
#else
|
||||
#error "Wrong SAMA_MOSC_SEL value."
|
||||
#endif /* SAMA_MOSCXTCLK */
|
||||
|
||||
#if (SAMA_MCK_SEL == SAMA_MCK_PLLA_CLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_ACTIVATE_PLLA TRUE
|
||||
#else
|
||||
#define SAMA_ACTIVATE_PLLA FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLAMUL field.
|
||||
*/
|
||||
#if ((SAMA_PLLA_MUL_VALUE >= 1) && (SAMA_PLLA_MUL_VALUE <= 127)) || \
|
||||
defined(__DOXYGEN__)
|
||||
#define SAMA_PLLA_MUL ((SAMA_PLLA_MUL_VALUE - 1) << 18)
|
||||
#else
|
||||
#error "invalid SAMA_PLLA_MUL_VALUE value specified"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLA input clock frequency.
|
||||
* @todo Consider to add DIVA to this. On SAMA5D27 DIVA is a nonsense since
|
||||
* it could be only 1 or 0 whereas 0 means PLLA disabled. This could
|
||||
* be useful for other chip belonging to this family
|
||||
*/
|
||||
#define SAMA_PLLACLKIN SAMA_MAIN_CLK
|
||||
|
||||
/* PLLA input frequency range check.*/
|
||||
#if (SAMA_PLLACLKIN < SAMA_PLLIN_MIN) || (SAMA_PLLACLKIN > SAMA_PLLIN_MAX)
|
||||
#error "SAMA_PLLACLKIN out of range"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLA output clock frequency.
|
||||
*/
|
||||
#define SAMA_PLLACLKOUT (SAMA_MAIN_CLK * SAMA_PLLA_MUL_VALUE)
|
||||
|
||||
/* PLLA output frequency range check.*/
|
||||
#if (SAMA_PLLACLKOUT < SAMA_PLLOUT_MIN) || (SAMA_PLLACLKOUT > SAMA_PLLOUT_MAX)
|
||||
#error "SAMA_PLLACLKOUT out of range"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PLLADIV2 divider value.
|
||||
*/
|
||||
#if SAMA_PLLADIV2_EN || defined(__DOXYGEN__)
|
||||
#define SAMA_PLLADIV2 SAMA_MCK_PLLADIV2
|
||||
#else
|
||||
#define SAMA_PLLADIV 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master Clock prescaler.
|
||||
*/
|
||||
#if (SAMA_MCK_PRES_VALUE == 1) || defined(__DOXYGEN__)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV1
|
||||
#elif (SAMA_MCK_PRES_VALUE == 2)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV2
|
||||
#elif (SAMA_MCK_PRES_VALUE == 4)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV4
|
||||
#elif (SAMA_MCK_PRES_VALUE == 8)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV8
|
||||
#elif (SAMA_MCK_PRES_VALUE == 16)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV16
|
||||
#elif (SAMA_MCK_PRES_VALUE == 32)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV32
|
||||
#elif (SAMA_MCK_PRES_VALUE == 64)
|
||||
#define SAMA_MCK_PRES SAMA_MCK_PRE_DIV64
|
||||
#else
|
||||
#error "Wrong SAMA_MCK_PRES_VALUE."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master Clock divider.
|
||||
*/
|
||||
#if (SAMA_MCK_MDIV_VALUE == 1) || defined(__DOXYGEN__)
|
||||
#define SAMA_MCK_MDIV SAMA_MCK_MDIV_DIV1
|
||||
#elif (SAMA_MCK_MDIV_VALUE == 2)
|
||||
#define SAMA_MCK_MDIV SAMA_MCK_MDIV_DIV2
|
||||
#elif (SAMA_MCK_MDIV_VALUE == 3)
|
||||
#define SAMA_MCK_MDIV SAMA_MCK_MDIV_DIV3
|
||||
#elif (SAMA_MCK_MDIV_VALUE == 4)
|
||||
#define SAMA_MCK_MDIV SAMA_MCK_MDIV_DIV4
|
||||
#else
|
||||
#error "Wrong SAMA_MCK_MDIV_VALUE."
|
||||
#endif
|
||||
|
||||
/* Check on MDIV and PLLADIV2 value. */
|
||||
#if (SAMA_MCK_MDIV == SAMA_MCK_MDIV_DIV3) && !SAMA_PLLADIV2_EN
|
||||
#error "PLLADIV2 must be always enabled when Main Clock Divider is 3"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Processor Clock frequency.
|
||||
*/
|
||||
#if (SAMA_MCK_SEL == SAMA_MCK_SLOW_CLK) || defined(__DOXYGEN__)
|
||||
#define SAMA_PCK (SAMA_SLOW_CLK / SAMA_MCK_PRES_VALUE)
|
||||
#elif (SAMA_MCK_SEL == SAMA_MCK_MAIN_CLK)
|
||||
#define SAMA_PCK (SAMA_MAIN_CLK / SAMA_MCK_PRES_VALUE)
|
||||
#elif (SAMA_MCK_SEL == SAMA_MCK_PLLA_CLK)
|
||||
#if SAMA_PLLADIV2_EN
|
||||
#define SAMA_PCK (SAMA_PLLACLKOUT / SAMA_MCK_PRES_VALUE / 2)
|
||||
#else
|
||||
#define SAMA_PCK (SAMA_PLLACLKOUT / SAMA_MCK_PRES_VALUE)
|
||||
#endif
|
||||
#elif (SAMA_MCK_SEL == SAMA_MCK_UPLL_CLK)
|
||||
#error "UPLL still unsupported"
|
||||
#else
|
||||
#error "Wrong SAMA_MCK_SEL."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master Clock frequency.
|
||||
*/
|
||||
#define SAMA_MCK (SAMA_PCK / SAMA_MCK_MDIV_VALUE)
|
||||
|
||||
/* Checks on Processor Clock crystal range. */
|
||||
#if (SAMA_PCK > SAMA_PCK_MAX) || (SAMA_PCK < SAMA_PCK_MIN)
|
||||
#error "Processor clock frequency out of range."
|
||||
#endif
|
||||
|
||||
/* Checks on Master Clock crystal range. */
|
||||
#if (SAMA_MCK > SAMA_MCK_MAX) || (SAMA_MCK < SAMA_MCK_MIN)
|
||||
#error "Master clock frequency out of range."
|
||||
#define VALUE(x) #x
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
#pragma message(VAR_NAME_VALUE(SAMA_MCK))
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Matrix H64H32 clock ratio.
|
||||
*/
|
||||
#if ((SAMA_H64MX_H32MX_RATIO == 2) || defined(__DOXYGEN__))
|
||||
#define SAMA_H64MX_H32MX_DIV PMC_MCKR_H32MXDIV_H32MXDIV2
|
||||
#elif (SAMA_H64MX_H32MX_RATIO == 1)
|
||||
#define SAMA_H64MX_H32MX_DIV PMC_MCKR_H32MXDIV_H32MXDIV1
|
||||
#if (SAMA_MCK > 83000000)
|
||||
#error "Invalid H32MXCLK. MCK > 83MHz wants SAMA_H64MX_H32MX_RATIO == 2"
|
||||
#endif
|
||||
#else
|
||||
#error "H64MX H32MX clock ratio out of range."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UARTx clock.
|
||||
* TODO: Work only with PERIPH CLOCK
|
||||
*/
|
||||
#define SAMA_UART0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_UART1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_UART2CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_UART3CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_UART4CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
/**
|
||||
* @brief FLEXCOMx clock.
|
||||
* TODO: Work only with PERIPH CLOCK
|
||||
*/
|
||||
#define SAMA_FLEXCOM0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_FLEXCOM1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_FLEXCOM2CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_FLEXCOM3CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_FLEXCOM4CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
/**
|
||||
* @brief TCx clock.
|
||||
* TODO: Work only with PERIPH CLOCK
|
||||
*/
|
||||
#define SAMA_TC0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
#define SAMA_TC1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
/**
|
||||
* @brief GMAC0 clock.
|
||||
* TODO: Work only with PERIPH CLOCK
|
||||
*/
|
||||
#define SAMA_GMAC0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
/**
|
||||
* @brief TWIHSx clock.
|
||||
* TODO: Work only with PERIPH CLOCK
|
||||
*/
|
||||
#define SAMA_TWIHSxCLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Various helpers.*/
|
||||
#include "sama_pmc.h"
|
||||
#include "sama_aic.h"
|
||||
#include "sama_matrix.h"
|
||||
#include "sama_xdmac.h"
|
||||
#include "sama_cache.h"
|
||||
#include "sama_tc_lld.h"
|
||||
#include "sama_lcdc.h"
|
||||
#include "sama_secumod.h"
|
||||
#include "sama_onewire.h"
|
||||
#include "sama_classd.h"
|
||||
#include "sama_rstc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void hal_lld_init(void);
|
||||
void sama_clock_init(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAL_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/hal_st_lld.c
|
||||
* @brief ST Driver subsystem low level driver code.
|
||||
*
|
||||
* @addtogroup ST
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Periodic Interrupt Timer frequency.
|
||||
*/
|
||||
#define SAMA_PIT (SAMA_MCK / 16 / SAMA_H64MX_H32MX_RATIO)
|
||||
|
||||
#if (SAMA_ST_USE_TC0 == TRUE) || (SAMA_ST_USE_TC1 == TRUE)
|
||||
/**
|
||||
* @brief Enable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tc pointer to a TC
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcEnableWP(tc) { \
|
||||
tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tc pointer to a TC
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcDisableWP(tc) { \
|
||||
tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
|
||||
|
||||
#if SAMA_ST_USE_PIT
|
||||
#error "PIT timer doesn't support tick-less mode"
|
||||
#endif
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
#if ((SAMA_TC0CLK) / (OSAL_ST_FREQUENCY) != 32)
|
||||
#error "Bad OSAL_ST_FREQUENCY value in configuration. It must be set to TC0_periph_clk / 32"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_ST_USE_TC1
|
||||
#if (((SAMA_TC1CLK) / (OSAL_ST_FREQUENCY) != 32) || ((SAMA_TC1CLK) % (OSAL_ST_FREQUENCY)) != 0)
|
||||
#error "Bad OSAL_ST_FREQUENCY value in configuration. It must be set to TC1_periph_clk / 32"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1
|
||||
static Tc *tcp;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief System Timer vector.
|
||||
* @details This interrupt is used both in periodic or free running
|
||||
* mode, generated by TCx timer.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_ST_TC_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
(void)tcp->TC_CHANNEL[0].TC_SR; /* acknowledge TC interrupt */
|
||||
osalSysLockFromISR();
|
||||
osalOsTimerHandlerI();
|
||||
osalSysUnlockFromISR();
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SAMA_ST_USE_PIT) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief System Timer vector.
|
||||
* @details This interrupt is used for system tick in periodic mode.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(PIT_Handler) {
|
||||
uint32_t ivr;
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
osalSysLockFromISR();
|
||||
ivr = PIT->PIT_PIVR; /* acknowledge PIT interrupt */
|
||||
osalDbgAssert((ivr & PIT_PIVR_PICNT_Msk) == (1 << PIT_PIVR_PICNT_Pos),
|
||||
"check for lost tick");
|
||||
osalOsTimerHandlerI();
|
||||
osalSysUnlockFromISR();
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* SAMA_ST_USE_PIT == TRUE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level ST driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void st_lld_init(void) {
|
||||
|
||||
#if SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
tcp = TC0;
|
||||
uint32_t rc = (SAMA_TC0CLK) / (OSAL_ST_FREQUENCY);
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
pmcEnableTC0();
|
||||
aicSetSourcePriority(ID_TC0, SAMA_TC0_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC0, SAMA_ST_TC_HANDLER);
|
||||
aicEnableInt(ID_TC0);
|
||||
#endif
|
||||
|
||||
#if SAMA_ST_USE_TC1
|
||||
tcp = TC1;
|
||||
uint32_t rc = (SAMA_TC1CLK) / (OSAL_ST_FREQUENCY);
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
pmcEnableTC1();
|
||||
aicSetSourcePriority(ID_TC1, SAMA_TC1_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC1, SAMA_ST_TC_HANDLER);
|
||||
aicEnableInt(ID_TC1);
|
||||
#endif
|
||||
|
||||
tcDisableWP(tcp);
|
||||
#if OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING
|
||||
|
||||
/* Initializing the timer counter in free running mode.
|
||||
* The clock source is the bus clock divided by 32.*/
|
||||
(void)rc;
|
||||
tcp->TC_CHANNEL[0].TC_EMR = 0;
|
||||
tcp->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_WAVSEL_UP |
|
||||
TC_CMR_TCCLKS(TC_CMR_TCCLKS_TIMER_CLOCK3);
|
||||
tcp->TC_CHANNEL[0].TC_RC = 0;
|
||||
tcp->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
|
||||
tcp->TC_CHANNEL[0].TC_IDR = 0xFFFFFFFF; /* Disable IRQs. */
|
||||
tcp->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */
|
||||
#endif
|
||||
|
||||
#if OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC
|
||||
tcp->TC_CHANNEL[0].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC;
|
||||
tcp->TC_CHANNEL[0].TC_RC = TC_RC_RC(rc);
|
||||
tcp->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;;
|
||||
tcp->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */
|
||||
tcp->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
|
||||
#endif
|
||||
|
||||
tcEnableWP(tcp);
|
||||
#endif /* SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1 */
|
||||
|
||||
#if (SAMA_ST_USE_PIT == TRUE)
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_PIT, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/* Enable PIT.*/
|
||||
pmcEnablePIT();
|
||||
PIT->PIT_MR = PIT_MR_PIV((SAMA_PIT / OSAL_ST_FREQUENCY) - 1);
|
||||
PIT->PIT_MR |= PIT_MR_PITEN | PIT_MR_PITIEN;
|
||||
(void) PIT->PIT_PIVR; /* reset PIT PICNT counter */
|
||||
|
||||
/* Enable IRQ.*/
|
||||
aicSetSourcePriority(ID_PIT, SAMA_ST_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_PIT, PIT_Handler);
|
||||
aicEnableInt(ID_PIT);
|
||||
#endif /* SAMA_ST_USE_PIT */
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/hal_st_lld.h
|
||||
* @brief ST Driver subsystem low level driver header.
|
||||
* @details This header is designed to be include-able without having to
|
||||
* include other files from the HAL.
|
||||
*
|
||||
* @addtogroup ST
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_ST_LLD_H
|
||||
#define HAL_ST_LLD_H
|
||||
|
||||
#include "mcuconf.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief SysTick timer IRQ priority.
|
||||
*/
|
||||
#if !defined(SAMA_ST_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_ST_IRQ_PRIORITY 0
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
/* Only one source for st */
|
||||
#if SAMA_ST_USE_TC0
|
||||
#if defined(ST_ASSIGNED)
|
||||
#error "ST already assigned"
|
||||
#else
|
||||
#define ST_ASSIGNED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Only one source for st */
|
||||
#if SAMA_ST_USE_TC1
|
||||
#if defined(ST_ASSIGNED)
|
||||
#error "ST already assigned"
|
||||
#else
|
||||
#define ST_ASSIGNED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Only one source for st */
|
||||
#if SAMA_ST_USE_PIT
|
||||
#if defined(ST_ASSIGNED)
|
||||
#error "ST already assigned"
|
||||
#else
|
||||
#define ST_ASSIGNED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of TCx units.*/
|
||||
#if SAMA_ST_USE_TC0
|
||||
#if defined(SAMA_TC0_IS_USED)
|
||||
#error "ST requires TC0 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_TC0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SAMA_ST_USE_TC1
|
||||
#if defined(SAMA_TC1_IS_USED)
|
||||
#error "ST requires TC1 but the peripheral is already used"
|
||||
#else
|
||||
#define SAMA_TC1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void st_lld_init(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Returns the time counter value.
|
||||
*
|
||||
* @return The counter value.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t st_lld_get_counter(void) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
return (systime_t)tcp->TC_CHANNEL[0].TC_CV;
|
||||
#else
|
||||
|
||||
return (systime_t)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the alarm.
|
||||
* @note Makes sure that no spurious alarms are triggered after
|
||||
* this call.
|
||||
*
|
||||
* @param[in] time the time to be set for the first alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void st_lld_start_alarm(systime_t time) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
|
||||
tcp->TC_CHANNEL[0].TC_RC = TC_RC_RC((uint32_t)time);
|
||||
tcp->TC_CHANNEL[0].TC_SR;
|
||||
tcp->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
|
||||
#else
|
||||
|
||||
(void)time;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the alarm interrupt.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void st_lld_stop_alarm(void) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
|
||||
tcp->TC_CHANNEL[0].TC_IDR = TC_IDR_CPCS;
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the alarm time.
|
||||
*
|
||||
* @param[in] time the time to be set for the next alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void st_lld_set_alarm(systime_t time) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
|
||||
tcp->TC_CHANNEL[0].TC_RC = TC_RC_RC((uint32_t)time);
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
|
||||
#else
|
||||
|
||||
(void)time;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current alarm time.
|
||||
*
|
||||
* @return The currently set alarm time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t st_lld_get_alarm(void) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
return (systime_t)tcp->TC_CHANNEL[0].TC_RC;
|
||||
#else
|
||||
|
||||
return (systime_t)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines if the alarm is active.
|
||||
*
|
||||
* @return The alarm status.
|
||||
* @retval false if the alarm is not active.
|
||||
* @retval true is the alarm is active
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline bool st_lld_is_alarm_active(void) {
|
||||
|
||||
#if (SAMA_ST_USE_TC0 || SAMA_ST_USE_TC1)
|
||||
|
||||
#if SAMA_ST_USE_TC0
|
||||
|
||||
Tc *tcp = TC0;
|
||||
#endif
|
||||
#if SAMA_ST_USE_TC1
|
||||
|
||||
Tc *tcp = TC1;
|
||||
#endif
|
||||
|
||||
return (bool)((tcp->TC_CHANNEL[0].TC_IMR & TC_IMR_CPCS) != 0);
|
||||
#else
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* HAL_ST_LLD_H */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -1,575 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/hal_tc_lld.c
|
||||
* @brief SAMA TC support code.
|
||||
*
|
||||
* @addtogroup TC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_TC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tcp pointer to a TC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcEnableWP(tcp) { \
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tcp pointer to a TC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcDisableWP(tcp) { \
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief TCD0 driver identifier.
|
||||
* @note The driver TCD0 allocates the timer TC0 when enabled.
|
||||
*/
|
||||
#if SAMA_USE_TC0 || defined(__DOXYGEN__)
|
||||
TCDriver TCD0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 driver identifier.
|
||||
* @note The driver TCD1 allocates the timer TC1 when enabled.
|
||||
*/
|
||||
#if SAMA_USE_TC1 || defined(__DOXYGEN__)
|
||||
TCDriver TCD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Common IRQ handler.
|
||||
* @note It is assumed that the various sources are only activated if the
|
||||
* associated callback pointer is not equal to @p NULL in order to not
|
||||
* perform an extra check in a potentially critical interrupt handler.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_serve_interrupt(TCDriver *tcp) {
|
||||
uint32_t sr, imr, i;
|
||||
|
||||
for (i = 0; i < TC_CHANNELS; i++) {
|
||||
sr = tcp->tim->TC_CHANNEL[i].TC_SR;
|
||||
imr = tcp->tim->TC_CHANNEL[i].TC_IMR;
|
||||
if (((sr & TC_SR_CPCS) != 0) && ((imr & TC_IMR_CPCS) != 0) &&
|
||||
(tcp->config->channels[i].callback != NULL)) {
|
||||
tcp->config->channels[i].callback(tcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_USE_TC0 || defined(__DOXYGEN__)
|
||||
#if !defined(SAMA_TC0_SUPPRESS_ISR)
|
||||
/**
|
||||
* @brief TC0 interrupt handler.
|
||||
* @note It is assumed that this interrupt is only activated if the callback
|
||||
* pointer is not equal to @p NULL in order to not perform an extra
|
||||
* check in a potentially critical interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TC0_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
tc_lld_serve_interrupt(&TCD0);
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* !defined(SAMA_TC0_SUPPRESS_ISR) */
|
||||
#endif /* SAMA_USE_TC0 */
|
||||
|
||||
#if SAMA_USE_TC1 || defined(__DOXYGEN__)
|
||||
#if !defined(SAMA_TC1_SUPPRESS_ISR)
|
||||
/**
|
||||
* @brief TC1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TC1_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
tc_lld_serve_interrupt(&TCD1);
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* !defined(SAMA_TC1_SUPPRESS_ISR) */
|
||||
#endif /* SAMA_USE_TC1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level TC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_init(void) {
|
||||
|
||||
#if SAMA_USE_TC0
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
tcObjectInit(&TCD0);
|
||||
TCD0.channels = TC_CHANNELS;
|
||||
TCD0.tim = TC0;
|
||||
TCD0.clock = SAMA_TC0CLK;
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
tcObjectInit(&TCD1);
|
||||
TCD1.channels = TC_CHANNELS;
|
||||
TCD1.tim = TC1;
|
||||
TCD1.clock = SAMA_TC1CLK;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_start(TCDriver *tcp) {
|
||||
uint32_t rc = 0;
|
||||
|
||||
if (tcp->state == TC_STOP) {
|
||||
/* Clock activation.*/
|
||||
#if SAMA_USE_TC0
|
||||
if (&TCD0 == tcp) {
|
||||
pmcEnableTC0();
|
||||
#if !defined(SAMA_TC0_SUPPRESS_ISR)
|
||||
aicSetSourcePriority(ID_TC0, SAMA_TC0_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC0, SAMA_TC0_HANDLER);
|
||||
aicEnableInt(ID_TC0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
if (&TCD1 == tcp) {
|
||||
pmcEnableTC1();
|
||||
#if !defined(SAMA_TC1_SUPPRESS_ISR)
|
||||
aicSetSourcePriority(ID_TC1, SAMA_TC1_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC1, SAMA_TC1_HANDLER);
|
||||
aicEnableInt(ID_TC1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* Disable Write Protection */
|
||||
tcDisableWP(tcp->tim);
|
||||
/* Output enables*/
|
||||
switch (tcp->config->channels[0].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[0].frequency);
|
||||
tcp->tim->TC_CHANNEL[0].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[0].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
switch (tcp->config->channels[1].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[1].frequency);
|
||||
tcp->tim->TC_CHANNEL[1].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[1].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[1].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[1].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
switch (tcp->config->channels[2].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[2].frequency);
|
||||
tcp->tim->TC_CHANNEL[2].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[2].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[2].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[2].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
/* Enable Write Protection */
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_stop(TCDriver *tcp) {
|
||||
|
||||
/* If in ready state then disables the TC clock.*/
|
||||
if (tcp->state == TC_READY) {
|
||||
#if SAMA_USE_TC0
|
||||
if (&TCD0 == tcp) {
|
||||
aicDisableInt(ID_TC0);
|
||||
pmcDisableTC0();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
if (&TCD1 == tcp) {
|
||||
aicDisableInt(ID_TC1);
|
||||
pmcDisableTC1();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note The function has effect at the next cycle start.
|
||||
* @note Channel notification is not enabled.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_enable_channel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width) {
|
||||
/* Disable Write Protection */
|
||||
tcDisableWP(tcp->tim);
|
||||
|
||||
/* Changing channel duty cycle on the fly.*/
|
||||
uint32_t rc = tcp->tim->TC_CHANNEL[channel].TC_RC;
|
||||
tcp->tim->TC_CHANNEL[channel].TC_RA = TC_RA_RA((100 - width) * rc / 100);
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKEN;
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_SWTRG;
|
||||
|
||||
/* Enable Write Protection */
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel and its notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note The function has effect at the next cycle start.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_disable_channel(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_enable_channel_notification(TCDriver *tcp,
|
||||
tcchannel_t channel) {
|
||||
tcp->tim->TC_CHANNEL[channel].TC_IER |= TC_IER_CPCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_disable_channel_notification(TCDriver *tcp,
|
||||
tcchannel_t channel) {
|
||||
|
||||
tcp->tim->TC_CHANNEL[channel].TC_IDR |= TC_IDR_CPCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes TC channel's frequency.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel must be enabled using @p tcEnableChannel().
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
*/
|
||||
|
||||
void tcChangeChannelFrequency(TCDriver *tcp,
|
||||
tcchannel_t channel,uint32_t frequency) {
|
||||
tcDisableWP(tcp->tim);
|
||||
uint32_t rc =(tcp->clock) / (frequency);
|
||||
tcp->tim->TC_CHANNEL[channel].TC_RC = TC_RC_RC(rc);
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
/**
|
||||
* @brief TC Driver initialization.
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void tcInit(void) {
|
||||
|
||||
tc_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the standard part of a @p TCDriver structure.
|
||||
*
|
||||
* @param[out] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void tcObjectInit(TCDriver *tcp) {
|
||||
|
||||
tcp->state = TC_STOP;
|
||||
tcp->config = NULL;
|
||||
tcp->enabled = 0;
|
||||
tcp->channels = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] config pointer to a @p TCConfig object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcStart(TCDriver *tcp, const TCConfig *config) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (config != NULL));
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
|
||||
"invalid state");
|
||||
tcp->config = config;
|
||||
tc_lld_start(tcp);
|
||||
tcp->enabled = 0;
|
||||
tcp->state = TC_READY;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcStop(TCDriver *tcp) {
|
||||
|
||||
osalDbgCheck(tcp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
|
||||
"invalid state");
|
||||
|
||||
tc_lld_stop(tcp);
|
||||
tcp->enabled = 0;
|
||||
tcp->config = NULL;
|
||||
tcp->state = TC_STOP;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcEnableChannel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
|
||||
tcEnableChannelI(tcp, channel, width);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel and its notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcDisableChannel(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
|
||||
tcDisableChannelI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
|
||||
"channel not enabled");
|
||||
osalDbgAssert(tcp->config->channels[channel].callback != NULL,
|
||||
"undefined channel callback");
|
||||
|
||||
tcEnableChannelNotificationI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
|
||||
"channel not enabled");
|
||||
osalDbgAssert(tcp->config->channels[channel].callback != NULL,
|
||||
"undefined channel callback");
|
||||
|
||||
tcDisableChannelNotificationI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_TC */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/hal_tc_lld.h
|
||||
* @brief SAMA TC subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup TC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_TC_LLD_H
|
||||
#define HAL_TC_LLD_H
|
||||
|
||||
#if HAL_USE_TC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of TC channels per TC driver.
|
||||
*/
|
||||
#define TC_CHANNELS TCCHANNEL_NUMBER
|
||||
|
||||
/**
|
||||
* @name TC output mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Standard output modes mask.
|
||||
*/
|
||||
#define TC_OUTPUT_MASK 0x0FU
|
||||
|
||||
/**
|
||||
* @brief Output not driven, callback only.
|
||||
*/
|
||||
#define TC_OUTPUT_DISABLED 0x00U
|
||||
|
||||
/**
|
||||
* @brief Output active.
|
||||
*/
|
||||
#define TC_OUTPUT_ACTIVE 0x01U
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
TC_UNINIT = 0, /**< Not initialized. */
|
||||
TC_STOP = 1, /**< Stopped. */
|
||||
TC_READY = 2 /**< Ready. */
|
||||
} tcstate_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing a TC driver.
|
||||
*/
|
||||
typedef struct TCDriver TCDriver;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC notification callback.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*/
|
||||
typedef void (*tccallback_t)(TCDriver *tcp);
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief TCD0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TCD0 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(SAMA_USE_TC0) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_TC0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TCD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(SAMA_USE_TC1) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_TC1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_TC0_IRQ_PRIORITY 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_TC1_IRQ_PRIORITY 2
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Configuration checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !SAMA_USE_TC0 && !SAMA_USE_TC1
|
||||
#error "TC driver activated but no TC peripheral assigned"
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of TCx units.*/
|
||||
#if SAMA_USE_TC0
|
||||
#if defined(SAMA_TC0_IS_USED)
|
||||
#error "TC0 is already used"
|
||||
#else
|
||||
#define SAMA_TC0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of TCx units.*/
|
||||
#if SAMA_USE_TC1
|
||||
#if defined(SAMA_TC1_IS_USED)
|
||||
#error "TC1 is already used"
|
||||
#else
|
||||
#define SAMA_TC1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a TC mode.
|
||||
*/
|
||||
typedef uint32_t tcmode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC channel.
|
||||
*/
|
||||
typedef uint8_t tcchannel_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a channels mask.
|
||||
*/
|
||||
typedef uint32_t tcchnmsk_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC counter.
|
||||
*/
|
||||
typedef uint32_t tccnt_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC driver channel configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channel active logic level.
|
||||
*/
|
||||
tcmode_t mode;
|
||||
/**
|
||||
* @brief Timer clock in Hz.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* frequency specifications.
|
||||
*/
|
||||
uint32_t frequency;
|
||||
/**
|
||||
* @brief Channel callback pointer.
|
||||
* @note This callback is invoked on the channel compare event. If set to
|
||||
* @p NULL then the callback is disabled.
|
||||
*/
|
||||
tccallback_t callback;
|
||||
/* End of the mandatory fields.*/
|
||||
} TCChannelConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channels configurations.
|
||||
*/
|
||||
TCChannelConfig channels[TC_CHANNELS];
|
||||
/* End of the mandatory fields.*/
|
||||
} TCConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a TC driver.
|
||||
*/
|
||||
struct TCDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
tcstate_t state;
|
||||
/**
|
||||
* @brief Current driver configuration data.
|
||||
*/
|
||||
const TCConfig *config;
|
||||
/**
|
||||
* @brief Mask of the enabled channels.
|
||||
*/
|
||||
tcchnmsk_t enabled;
|
||||
/**
|
||||
* @brief Number of channels in this instance.
|
||||
*/
|
||||
tcchannel_t channels;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Timer base clock.
|
||||
*/
|
||||
uint32_t clock;
|
||||
/**
|
||||
* @brief Pointer to the TCx registers block.
|
||||
*/
|
||||
Tc *tim;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcEnableChannelI(tcp, channel, width) do { \
|
||||
(tcp)->enabled |= ((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
|
||||
tc_lld_enable_channel(tcp, channel, width); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcDisableChannelI(tcp, channel) do { \
|
||||
(tcp)->enabled &= ~((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
|
||||
tc_lld_disable_channel(tcp, channel); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Returns a TC channel status.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcIsChannelEnabledI(tcp, channel) \
|
||||
(((tcp)->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)(channel))) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcEnableChannelNotificationI(tcp, channel) \
|
||||
tc_lld_enable_channel_notification(tcp, channel)
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcDisableChannelNotificationI(tcp, channel) \
|
||||
tc_lld_disable_channel_notification(tcp, channel)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_USE_TC0 && !defined(__DOXYGEN__)
|
||||
extern TCDriver TCD0;
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1 && !defined(__DOXYGEN__)
|
||||
extern TCDriver TCD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void tcInit(void);
|
||||
void tcObjectInit(TCDriver *tcp);
|
||||
void tcStart(TCDriver *tcp, const TCConfig *config);
|
||||
void tcStop(TCDriver *tcp);
|
||||
void tcEnableChannel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width);
|
||||
void tcDisableChannel(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcChangeChannelFrequency(TCDriver *tcp, tcchannel_t channel, uint32_t frequency);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_TC */
|
||||
|
||||
#endif /* HAL_TC_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,47 +0,0 @@
|
|||
# Required platform files.
|
||||
|
||||
PLATFORMSRC := $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_st_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_matrix.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_classd.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c
|
||||
|
||||
# Required include directories.
|
||||
PLATFORMINC := $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x
|
||||
|
||||
# Optional platform files.
|
||||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
|
||||
# Configuration files directory
|
||||
ifeq ($(CONFDIR),)
|
||||
CONFDIR = .
|
||||
endif
|
||||
|
||||
HALCONF := $(strip $(shell cat $(CONFDIR)/halconf.h | egrep -e "\#define"))
|
||||
|
||||
else
|
||||
endif
|
||||
|
||||
# Drivers compatible with the platform.
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/PIOv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/QUADSPIv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/SPIv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/RTCv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk
|
||||
include $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/driver.mk
|
||||
|
||||
# Shared variables
|
||||
ALLCSRC += $(PLATFORMSRC)
|
||||
ALLINC += $(PLATFORMINC)
|
|
@ -1,310 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/aic.c
|
||||
* @brief SAMA AIC support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_AIC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on AIC registers block.
|
||||
*
|
||||
* @param[in] aicp pointer to a AIC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define aicEnableWP(aicp) { \
|
||||
aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD | AIC_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on AIC registers block.
|
||||
*
|
||||
* @param[in] aicp pointer to a AIC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define aicDisableWP(aicp) { \
|
||||
aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a IRQ priority is within the valid range.
|
||||
* @param[in] prio IRQ priority
|
||||
*
|
||||
* @retval The check result.
|
||||
* @retval FALSE invalid IRQ priority.
|
||||
* @retval TRUE correct IRQ priority.
|
||||
*/
|
||||
#define SAMA_IRQ_IS_VALID_PRIORITY(prio) ((prio) <= 7U)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static OSAL_IRQ_HANDLER(aicSpuriousHandler) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
osalSysHalt("Spurious interrupt");
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
static OSAL_IRQ_HANDLER(aicUnexpectedHandler) {
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
osalSysHalt("Unexpected interrupt");
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AIC Initialization.
|
||||
* @note Better reset everything in the AIC.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void aicInit(void) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
aicDisableWP(aic);
|
||||
|
||||
aic->AIC_SPU = (uint32_t)aicSpuriousHandler;
|
||||
aic->AIC_SSR = 0;
|
||||
aic->AIC_SVR = (uint32_t)aicUnexpectedHandler;
|
||||
|
||||
unsigned i;
|
||||
/* Disable all interrupts */
|
||||
for (i = 1; i < ID_PERIPH_COUNT; i++) {
|
||||
aic->AIC_SSR = i;
|
||||
aic->AIC_IDCR = AIC_IDCR_INTD;
|
||||
|
||||
/* Changes type */
|
||||
aic->AIC_SMR = AIC_SMR_SRCTYPE(EXT_NEGATIVE_EDGE);
|
||||
|
||||
/* Clear pending interrupt */
|
||||
aic->AIC_ICCR = AIC_ICCR_INTCLR;
|
||||
|
||||
/* Changes type */
|
||||
aic->AIC_SMR = AIC_SMR_SRCTYPE(INT_LEVEL_SENSITIVE);
|
||||
|
||||
/* Default handler */
|
||||
aic->AIC_SVR = (uint32_t)aicUnexpectedHandler;
|
||||
}
|
||||
aicEnableWP(aic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures an interrupt in the AIC.
|
||||
* @note Source cannot be ID_SAIC_FIQ (0).
|
||||
*
|
||||
* @param[in] source interrupt source to configure
|
||||
* @param[in] priority priority level of the selected source.
|
||||
*/
|
||||
void aicSetSourcePriority(uint32_t source, uint8_t priority) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
osalDbgCheck(source != ID_SAIC_FIQ);
|
||||
osalDbgAssert(SAMA_IRQ_IS_VALID_PRIORITY(priority), "invalid irq priority");
|
||||
/* Disable write protection */
|
||||
aicDisableWP(aic);
|
||||
/* Set source id */
|
||||
aic->AIC_SSR = source;
|
||||
/* Disable the interrupt first */
|
||||
aic->AIC_IDCR = AIC_IDCR_INTD;
|
||||
/* Configure priority */
|
||||
aic->AIC_SMR |= AIC_SMR_PRIOR(priority);
|
||||
/* Clear interrupt */
|
||||
aic->AIC_ICCR = AIC_ICCR_INTCLR;
|
||||
/* Enable write protection */
|
||||
aicEnableWP(aic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures type of interrupt in the AIC.
|
||||
*
|
||||
* @param[in] source interrupt source to configure
|
||||
* @param[in] type type interrupt of the selected source.
|
||||
*/
|
||||
void aicSetIntSourceType(uint32_t source, uint8_t type) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
/* Disable write protection */
|
||||
aicDisableWP(aic);
|
||||
/* Set source id */
|
||||
aic->AIC_SSR = source;
|
||||
/* Disable the interrupt first */
|
||||
aic->AIC_IDCR = AIC_IDCR_INTD;
|
||||
/* Configure priority */
|
||||
aic->AIC_SMR |= AIC_SMR_SRCTYPE(type);
|
||||
/* Clear interrupt */
|
||||
aic->AIC_ICCR = AIC_ICCR_INTCLR;
|
||||
/* Enable write protection */
|
||||
aicEnableWP(aic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the source handler of an interrupt.
|
||||
*
|
||||
* @param[in] source interrupt source to configure
|
||||
* @param[in] handler handler for the interrupt source selected
|
||||
*/
|
||||
void aicSetSourceHandler(uint32_t source, bool (*handler)(void)) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
/* Disable write protection */
|
||||
aicDisableWP(aic);
|
||||
/* Select source and assign handler */
|
||||
aic->AIC_SSR = AIC_SSR_INTSEL(source);
|
||||
aic->AIC_SVR = (uint32_t)handler;
|
||||
/* Enable write protection */
|
||||
aicEnableWP(aic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the spurious handler of an interrupt.
|
||||
*
|
||||
* @param[in] handler handler for the interrupt
|
||||
*/
|
||||
void aicSetSpuriousHandler(bool (*handler)(void)) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
/* Disable write protection */
|
||||
aicDisableWP(aic);
|
||||
/* Assign handler */
|
||||
aic->AIC_SPU = (uint32_t)handler;
|
||||
/* Enable write protection */
|
||||
aicEnableWP(aic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables interrupts coming from the source.
|
||||
*
|
||||
* @param[in] source interrupt source to enable
|
||||
*/
|
||||
void aicEnableInt(uint32_t source) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
aic->AIC_SSR = AIC_SSR_INTSEL(source);
|
||||
aic->AIC_IECR = AIC_IECR_INTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables interrupts coming from the selected source.
|
||||
*
|
||||
* @param[in] source interrupt source to disable
|
||||
*/
|
||||
void aicDisableInt(uint32_t source) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
aic->AIC_SSR = AIC_SSR_INTSEL(source);
|
||||
aic->AIC_IDCR = AIC_IDCR_INTD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears interrupts coming from the selected source.
|
||||
*
|
||||
* @param[in] source interrupt source to Clear
|
||||
*/
|
||||
void aicClearInt(uint32_t source) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
aic->AIC_SSR = AIC_SSR_INTSEL(source);
|
||||
aic->AIC_ICCR = AIC_ICCR_INTCLR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets interrupts coming from the selected source.
|
||||
*
|
||||
* @param[in] source interrupt source to Set
|
||||
*/
|
||||
void aicSetInt(uint32_t source) {
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
Aic *aic = SAIC;
|
||||
#else
|
||||
Aic *aic = AIC;
|
||||
#endif
|
||||
|
||||
aic->AIC_SSR = AIC_SSR_INTSEL(source);
|
||||
aic->AIC_ISCR = AIC_ISCR_INTSET;
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/aic.h
|
||||
* @brief SAMA AIC support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_AIC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef AIC_H
|
||||
#define AIC_H
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name INTERRUPT SOURCE TYPE mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief High-level sensitive for internal source.
|
||||
* Low-level sensitive for external source.
|
||||
*/
|
||||
#define INT_LEVEL_SENSITIVE 0x0U
|
||||
|
||||
/**
|
||||
* @brief Negative-edge triggered for external source.
|
||||
*/
|
||||
#define EXT_NEGATIVE_EDGE 0x1U
|
||||
|
||||
/**
|
||||
* @brief High-level sensitive for internal source.
|
||||
* High-level sensitive for external source.
|
||||
*/
|
||||
#define EXT_HIGH_LEVEL 0x2U
|
||||
|
||||
/**
|
||||
* @brief Positive-edge triggered for external source.
|
||||
*/
|
||||
#define EXT_POSITIVE_EDGE 0x3U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief AIC unique redirect key.
|
||||
*/
|
||||
#define AIC_REDIR_KEY 0x5B6C0E26U
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Acknowledge the current interrupt.
|
||||
*/
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define aicAckInt() { \
|
||||
SAIC->AIC_EOICR = AIC_EOICR_ENDIT; \
|
||||
}
|
||||
#else
|
||||
#define aicAckInt() { \
|
||||
AIC->AIC_EOICR = AIC_EOICR_ENDIT; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void aicInit(void);
|
||||
void aicSetSourcePriority(uint32_t source, uint8_t priority);
|
||||
void aicSetIntSourceType(uint32_t source, uint8_t type);
|
||||
void aicSetSourceHandler(uint32_t source, bool (*handler)(void));
|
||||
void aicSetSpuriousHandler(bool (*handler)(void));
|
||||
void aicEnableInt(uint32_t source);
|
||||
void aicDisableInt(uint32_t source);
|
||||
void aicClearInt(uint32_t source);
|
||||
void aicSetInt(uint32_t source);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AIC_H */
|
||||
|
||||
/** @} */
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_cache.c
|
||||
* @brief SAMA CACHE support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_CACHE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if !defined(SAMA_L2CC_ASSUME_ENABLED)
|
||||
#define SAMA_L2CC_ASSUME_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA_L2CC_ENABLE)
|
||||
#define SAMA_L2CC_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Invalidate D-Cache Region
|
||||
*
|
||||
* @param[in] start Pointer to beginning of memory region.
|
||||
* @param[in] length Length of the memory location.
|
||||
*/
|
||||
void cacheInvalidateRegion(void *start, uint32_t length) {
|
||||
|
||||
uint32_t start_addr = (uint32_t)start;
|
||||
uint32_t end_addr = start_addr + length;
|
||||
uint32_t mva;
|
||||
|
||||
/* Invalidate L1 D-Cache */
|
||||
for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) {
|
||||
L1C_InvalidateDCacheMVA((uint32_t *)mva);
|
||||
}
|
||||
#if ARM_SUPPORTS_L2CC
|
||||
#if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE
|
||||
/* Invalidate L2 Cache */
|
||||
for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) {
|
||||
L2C_InvPa((uint32_t *)mva);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clean D-Cache Region
|
||||
*
|
||||
* @param[in] start Pointer to beginning of memory region.
|
||||
* @param[in] length Length of the memory location.
|
||||
*/
|
||||
void cacheCleanRegion(void *start, uint32_t length) {
|
||||
|
||||
uint32_t start_addr = (uint32_t)start;
|
||||
uint32_t end_addr = start_addr + length;
|
||||
uint32_t mva;
|
||||
|
||||
/* Clean L1 D-Cache */
|
||||
for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) {
|
||||
L1C_CleanDCacheMVA((uint32_t *)mva);
|
||||
}
|
||||
#if ARM_SUPPORTS_L2CC
|
||||
#if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE
|
||||
/* Invalidate L2 Cache */
|
||||
for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) {
|
||||
L2C_CleanPa((uint32_t *)mva);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clean and Invalidate D-Cache Region
|
||||
*
|
||||
* @param[in] start Pointer to beginning of memory region.
|
||||
* @param[in] length Length of the memory location.
|
||||
*/
|
||||
void cacheCleanInvalidateRegion(void *start, uint32_t length) {
|
||||
|
||||
uint32_t start_addr = (uint32_t)start;
|
||||
uint32_t end_addr = start_addr + length;
|
||||
uint32_t mva;
|
||||
|
||||
/* Clean L1 D-Cache */
|
||||
for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) {
|
||||
L1C_CleanInvalidateDCacheMVA((uint32_t *)mva);
|
||||
}
|
||||
#if ARM_SUPPORTS_L2CC
|
||||
#if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE
|
||||
/* Invalidate L2 Cache */
|
||||
for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) {
|
||||
L2C_CleanInvPa((uint32_t *)mva);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_cache.h
|
||||
* @brief SAMA CACHE support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_CACHE
|
||||
* @{
|
||||
*/
|
||||
#ifndef SAMA_CACHE_H_
|
||||
#define SAMA_CACHE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
#define L1_CACHE_BYTES 32u
|
||||
#define L2_CACHE_BYTES 32u
|
||||
|
||||
#define CACHE_ALIGNED ALIGNED_VAR(L1_CACHE_BYTES)
|
||||
#define NO_CACHE __attribute__((section (".nocache")))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern void cacheInvalidateRegion(void *start, uint32_t length);
|
||||
extern void cacheCleanRegion(void *start, uint32_t length);
|
||||
extern void cacheCleanInvalidateRegion(void *start, uint32_t length);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_CACHE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,526 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_classd.c
|
||||
* @brief SAMA CLASSD support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_CLASSD
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if SAMA_USE_CLASSD || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on CLASSD Mode Register
|
||||
* and Interpolator Mode Register.
|
||||
*
|
||||
* @param[in] classdp pointer to a CLASSD register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define classdEnableWP(classdp) { \
|
||||
classdp->CLASSD_WPMR = CLASSD_WPMR_WPKEY_PASSWD | CLASSD_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on CLASSD Mode Register
|
||||
* and Interpolator Mode Register.
|
||||
*
|
||||
* @param[in] classdp pointer to a CLASSD register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define classdDisableWP(classdp) { \
|
||||
classdp->CLASSD_WPMR = CLASSD_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief CLASSD driver identifier.
|
||||
*/
|
||||
CLASSDDriver CLASSDD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Type of a structure representing PMC Audio configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Loop Divider Ratio.
|
||||
*/
|
||||
uint32_t nd;
|
||||
|
||||
/**
|
||||
* @brief Fractional Loop Divider Setting.
|
||||
*/
|
||||
uint32_t fracr;
|
||||
|
||||
/**
|
||||
* @brief Output Divider Ratio for PMC Clock.
|
||||
*/
|
||||
uint32_t qdpmc;
|
||||
|
||||
/**
|
||||
* @brief Divider Value.
|
||||
*/
|
||||
uint32_t div;
|
||||
|
||||
/**
|
||||
* @brief Output Divider Ratio for Pad Clock.
|
||||
*/
|
||||
uint32_t qdaudio;
|
||||
} pmcAudioConf;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Configure DSPClock.
|
||||
*
|
||||
* @param[in] dsp_clk DSP clock type (12.288 MHz or 11.2896 MHz).
|
||||
*/
|
||||
static void dspclkConfigure(uint32_t dsp_clk) {
|
||||
pmcAudioConf cfg;
|
||||
|
||||
/* Pad Clock: not used */
|
||||
cfg.div = 0;
|
||||
cfg.qdaudio = 0;
|
||||
|
||||
/* PMC Clock: */
|
||||
/* 12Mhz * (ND + 1 + FRACR/2^22) / (QDPMC + 1) = 8 * DSPCLK */
|
||||
switch (dsp_clk) {
|
||||
case CLASSD_INTPMR_DSPCLKFREQ_12M288:
|
||||
#if SAMA_MOSCXTCLK == 12000000
|
||||
/* 12Mhz * (56 + 1 + 1442841/2^22) / (6 + 1) = 8 * 12.288Mhz */
|
||||
cfg.nd = 56;
|
||||
cfg.fracr = 1442841;
|
||||
cfg.qdpmc = 6;
|
||||
#elif SAMA_MOSCXTCLK == 24000000
|
||||
/* 24Mhz * (56 + 1 + 1442841/2^22) / (6 + 1) = 8 * 12.288Mhz */
|
||||
cfg.nd = 27;
|
||||
cfg.fracr = 2796203;
|
||||
cfg.qdpmc = 6;
|
||||
#else
|
||||
#error "FREQUENCY NOT SUPPORTED BY CLASSD"
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CLASSD_INTPMR_DSPCLKFREQ_11M2896:
|
||||
#if SAMA_MOSCXTCLK == 12000000
|
||||
/* 12Mhz * (59 + 1 + 885837/2^22) / (7 + 1) = 8 * 11.2896Mhz */
|
||||
cfg.nd = 59;
|
||||
cfg.fracr = 885837;
|
||||
cfg.qdpmc = 7;
|
||||
#elif SAMA_MOSCXTCLK == 24000000
|
||||
/* 24Mhz * (59 + 1 + 885837/2^22) / (7 + 1) = 8 * 11.2896Mhz */
|
||||
cfg.nd = 28;
|
||||
cfg.fracr = 699050;
|
||||
cfg.qdpmc = 7;
|
||||
#else
|
||||
#error "FREQUENCY NOT SUPPORTED BY CLASSD"
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
osalDbgAssert(NULL, "errore mask configuration");
|
||||
}
|
||||
|
||||
/* Configure and enable the generic clock. */
|
||||
pmcConfigAudio(cfg.nd, cfg.qdpmc, cfg.fracr, cfg.div, cfg.qdaudio);
|
||||
pmcEnableAudio(true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shared end-of-tx service routine.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
* @param[in] flags pre-shifted content of the ISR register
|
||||
*/
|
||||
static void classd_lld_serve_tx_interrupt(CLASSDDriver *classdp, uint32_t flags) {
|
||||
|
||||
/* DMA errors handling.*/
|
||||
#if defined(SAMA_CLASSD_DMA_ERROR_HOOK)
|
||||
(void)classdp;
|
||||
if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) {
|
||||
SAMA_CLASSD_DMA_ERROR_HOOK(classdp);
|
||||
}
|
||||
#else
|
||||
(void)flags;
|
||||
#endif
|
||||
|
||||
if(classdp->config->callback != NULL) {
|
||||
classdp->config->callback(classdp);
|
||||
}
|
||||
classdMuteChannel(classdp, false, false);
|
||||
classdp->state = CLASSD_READY;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level CLASSD driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classd_lld_init(void) {
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_CLASSD, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization. */
|
||||
classdObjectInit(&CLASSDD0);
|
||||
CLASSDD0.classd = CLASSD;
|
||||
CLASSDD0.dmatx = NULL;
|
||||
CLASSDD0.txdmamode = XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_MEM2PER |
|
||||
XDMAC_CC_PROT_SEC |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_WORD |
|
||||
XDMAC_CC_SIF_AHB_IF0 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_INCREMENTED_AM |
|
||||
XDMAC_CC_DAM_FIXED_AM |
|
||||
XDMAC_CC_PERID(PERID_CLASSD_TX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the CLASSD peripheral.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classd_lld_start(CLASSDDriver *classdp) {
|
||||
|
||||
uint8_t i;
|
||||
uint32_t dsp_clk_set, frame_set;
|
||||
|
||||
/* Configures the peripheral.*/
|
||||
if (classdp->state == CLASSD_STOP) {
|
||||
|
||||
if (&CLASSDD0 == classdp) {
|
||||
classdp->dmatx = dmaChannelAllocate(SAMA_CLASSD_DMA_IRQ_PRIORITY,
|
||||
(sama_dmaisr_t)classd_lld_serve_tx_interrupt,
|
||||
(void *)classdp);
|
||||
osalDbgAssert(classdp->dmatx != NULL, "no channel allocated");
|
||||
}
|
||||
}
|
||||
|
||||
/* Set DMA channel mode. */
|
||||
dmaChannelSetMode(classdp->dmatx, classdp->txdmamode);
|
||||
|
||||
/* Set CLASSD DSP clock and Sample rate. */
|
||||
for(i = 0; i < 8; i++) {
|
||||
if ((audio_info[i].rate) == (classdp->config->frame)) {
|
||||
dsp_clk_set = audio_info[i].dsp_clk;
|
||||
frame_set = audio_info[i].sample_rate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the CLASSD0 clock. */
|
||||
pmcEnableCLASSD0();
|
||||
|
||||
/* Configure PMC Audio structure. */
|
||||
dspclkConfigure(dsp_clk_set);
|
||||
|
||||
/* Disable the CLASSD generic clock for now. */
|
||||
pmcDisableGclkCLASSD0();
|
||||
|
||||
/* Configure the CLASSD generic clock */
|
||||
pmcConfigGclk(ID_CLASSD, PMC_PCR_GCKCSS_AUDIO_CLK, 1);
|
||||
|
||||
/* Disable write protection. */
|
||||
classdDisableWP(classdp->classd);
|
||||
|
||||
/* Perform soft reset. */
|
||||
CLASSD->CLASSD_CR = CLASSD_CR_SWRST;
|
||||
CLASSD->CLASSD_IDR = CLASSD_IDR_DATRDY;
|
||||
|
||||
/* Clean CLASSD Registers. */
|
||||
classdp->classd->CLASSD_MR = 0;
|
||||
classdp->classd->CLASSD_INTPMR = 0;
|
||||
|
||||
/* CLASSD configuration. */
|
||||
classdp->classd->CLASSD_MR = classdp->config->left |
|
||||
classdp->config->right |
|
||||
classdp->config->left_mute |
|
||||
classdp->config->right_mute |
|
||||
classdp->config->pwm_mode |
|
||||
classdp->config->non_overlap |
|
||||
classdp->config->novrval;
|
||||
|
||||
classdp->classd->CLASSD_INTPMR = classdp->config->attl |
|
||||
classdp->config->attr |
|
||||
classdp->config->deemp |
|
||||
classdp->config->swap |
|
||||
classdp->config->eqcfg |
|
||||
classdp->config->mono |
|
||||
classdp->config->mono_mode |
|
||||
dsp_clk_set | frame_set;
|
||||
|
||||
/* Enable CLASSD generic clock. */
|
||||
pmcEnableGclkCLASSD0();
|
||||
|
||||
/* Enable write protection. */
|
||||
classdEnableWP(classdp->classd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the CLASSD peripheral.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classd_lld_stop(CLASSDDriver *classdp) {
|
||||
|
||||
/* Disable clocks. */
|
||||
pmcDisableAudio();
|
||||
pmcDisableGclkCLASSD0();
|
||||
pmcDisableCLASSD0();
|
||||
|
||||
/* Disable write protection. */
|
||||
classdDisableWP(classdp->classd);
|
||||
|
||||
/* Reset CLASSD. */
|
||||
classdp->classd->CLASSD_INTPMR = 0;
|
||||
classdp->classd->CLASSD_MR = 0;
|
||||
|
||||
/* Enable write protection. */
|
||||
classdEnableWP(classdp->classd);
|
||||
|
||||
/* Release and disable DMA channel. */
|
||||
dmaChannelRelease(classdp->dmatx);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Starts a CLASSD playback.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classd_lld_send_audio(CLASSDDriver *classdp, const void *txbuf) {
|
||||
|
||||
/* Get DMA transfert size. */
|
||||
size_t n = ((struct wav_header *)txbuf)->subchunk2_size / 4;
|
||||
|
||||
osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned");
|
||||
|
||||
#if 0
|
||||
osalDbgAssert(!(n & (L1_CACHE_BYTES - 1)), "size not multiple of cache line");
|
||||
#endif
|
||||
|
||||
/* L1 is enabled */
|
||||
cacheCleanRegion((uint8_t *) txbuf, n);
|
||||
|
||||
/* Get source address. */
|
||||
uint32_t addrSource = sizeof(struct wav_header);
|
||||
|
||||
/* Unmute left and right channel */
|
||||
classdMuteChannel(classdp, false, false);
|
||||
|
||||
/* Writing channel */
|
||||
dmaChannelSetSource(classdp->dmatx, txbuf + addrSource);
|
||||
dmaChannelSetDestination(classdp->dmatx, &classdp->classd->CLASSD_THR);
|
||||
dmaChannelSetTransactionSize(classdp->dmatx, n);
|
||||
|
||||
/* DMA start transfer. */
|
||||
dmaChannelEnable(classdp->dmatx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CLASSD mute/unmute channels.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void classd_mute_channel(CLASSDDriver *classdp, bool left, bool right) {
|
||||
|
||||
/* Disable write protection. */
|
||||
classdDisableWP(classdp->classd);
|
||||
|
||||
/* Mute or unmute left channel. */
|
||||
if (left)
|
||||
classdp->classd->CLASSD_MR |= CLASSD_MR_LMUTE;
|
||||
else
|
||||
classdp->classd->CLASSD_MR &= ~CLASSD_MR_LMUTE;
|
||||
|
||||
/* Mute or unmute right channel. */
|
||||
if (right)
|
||||
classdp->classd->CLASSD_MR |= CLASSD_MR_RMUTE;
|
||||
else
|
||||
classdp->classd->CLASSD_MR &= ~CLASSD_MR_RMUTE;
|
||||
|
||||
/* Enable write protection. */
|
||||
classdEnableWP(classdp->classd);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief CLASSD Driver initialization.
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void classdInit(void) {
|
||||
|
||||
classd_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Initializes the standard part of a @p CLASSDDriver structure.
|
||||
*
|
||||
* @param[out] classdp pointer to a @p CLASSDDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void classdObjectInit(CLASSDDriver *classdp) {
|
||||
classdp->state = CLASSD_STOP;
|
||||
classdp->config = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the CLASSD peripheral.
|
||||
*
|
||||
* @param[in] classdp pointer to a @p CLASSDDriver object
|
||||
* @param[in] config pointer to a @p CLASSDConfig object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void classdStart(CLASSDDriver *classdp, const CLASSDConfig *config) {
|
||||
|
||||
osalDbgCheck((classdp != NULL) && (config != NULL));
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((classdp->state == CLASSD_STOP) || (classdp->state == CLASSD_READY),
|
||||
"invalid state");
|
||||
classdp->config = config;
|
||||
classd_lld_start(classdp);
|
||||
classdp->state = CLASSD_READY;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the CLASSD peripheral.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void classdStop(CLASSDDriver *classdp) {
|
||||
|
||||
osalDbgCheck(classdp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert((classdp->state == CLASSD_STOP) || (classdp->state == CLASSD_READY || (classdp->state == CLASSD_ACTIVE)),
|
||||
"invalid state");
|
||||
|
||||
classd_lld_stop(classdp);
|
||||
classdp->config = NULL;
|
||||
classdp->state = CLASSD_STOP;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Starts a CLASSD playback.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
*
|
||||
* @note This function can be used only in syslock state. todo: control comment!
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classdSendAudioI(CLASSDDriver *classdp, const void *txbuf) {
|
||||
|
||||
(classdp)->state = CLASSD_ACTIVE;
|
||||
classd_lld_send_audio(classdp, txbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Starts a CLASSD playback.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classdSendAudio(CLASSDDriver *classdp, const void *txbuf) {
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert(classdp->state == CLASSD_READY, "not ready");
|
||||
classdSendAudioI(classdp, txbuf);
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Set the sample frame from the structure of a wav file.
|
||||
*
|
||||
* @param[in] classdconfigp pointer to the @p CLASSDConfig
|
||||
* @param[in] music_file pointer to the wav file
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void classdSetSampleFrame(CLASSDConfig *classdconfigp, uint8_t *music_file) {
|
||||
classdconfigp->frame = ((struct wav_header*)music_file)->sample_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mute/unmute CLASSD channel.
|
||||
*
|
||||
* @param[in] classdp pointer to the @p CLASSDDriver object
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void classdMuteChannel(CLASSDDriver *classdp, bool left, bool right) {
|
||||
classd_mute_channel(classdp, left, right);
|
||||
}
|
||||
|
||||
#endif /* SAMA_USE_CLASSD */
|
||||
|
||||
/** @} */
|
|
@ -1,301 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_classd.h
|
||||
* @brief SAMA CLASSD support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_CLASSD
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_CLASSD_LLD_H
|
||||
#define SAMA_CLASSD_LLD_H
|
||||
|
||||
/**
|
||||
* @brief Using the CLASSD driver.
|
||||
*/
|
||||
#if !defined(SAMA_USE_CLASSD) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_CLASSD FALSE
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_CLASSD || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief CLASSD DMA interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_CLASSD_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_CLASSD_DMA_IRQ_PRIORITY 4
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(SAMA_DMA_REQUIRED)
|
||||
#define SAMA_DMA_REQUIRED
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
CLASSD_UNINIT = 0, /**< Not initialized. */
|
||||
CLASSD_STOP = 1, /**< Stopped. */
|
||||
CLASSD_READY = 2, /**< Ready. */
|
||||
CLASSD_ACTIVE = 3, /**< Exchanging data. */
|
||||
} classdstate_t;
|
||||
|
||||
/**
|
||||
* @brief Structure representing audio info.
|
||||
*/
|
||||
static const struct {
|
||||
/**
|
||||
* @brief Contains the value of the Sample Rate.
|
||||
*/
|
||||
uint32_t rate;
|
||||
/**
|
||||
* @brief Contains a mask of the Sample Rate.
|
||||
*/
|
||||
uint32_t sample_rate;
|
||||
/**
|
||||
* @brief Contains a mask of the DSP Clock.
|
||||
*/
|
||||
uint32_t dsp_clk;
|
||||
} audio_info[] = {
|
||||
{8000, CLASSD_INTPMR_FRAME_FRAME_8K, CLASSD_INTPMR_DSPCLKFREQ_12M288},
|
||||
{16000, CLASSD_INTPMR_FRAME_FRAME_16K, CLASSD_INTPMR_DSPCLKFREQ_12M288},
|
||||
{32000, CLASSD_INTPMR_FRAME_FRAME_32K, CLASSD_INTPMR_DSPCLKFREQ_12M288},
|
||||
{48000, CLASSD_INTPMR_FRAME_FRAME_48K, CLASSD_INTPMR_DSPCLKFREQ_12M288},
|
||||
{96000, CLASSD_INTPMR_FRAME_FRAME_96K, CLASSD_INTPMR_DSPCLKFREQ_12M288},
|
||||
{22050, CLASSD_INTPMR_FRAME_FRAME_22K, CLASSD_INTPMR_DSPCLKFREQ_11M2896},
|
||||
{44100, CLASSD_INTPMR_FRAME_FRAME_44K, CLASSD_INTPMR_DSPCLKFREQ_11M2896},
|
||||
{88200, CLASSD_INTPMR_FRAME_FRAME_88K, CLASSD_INTPMR_DSPCLKFREQ_11M2896},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing Standard WAV file header information.
|
||||
*/
|
||||
struct wav_header {
|
||||
/**
|
||||
* @brief Contains the letters "RIFF" in ASCII form.
|
||||
*/
|
||||
uint32_t chunk_id;
|
||||
/**
|
||||
* @brief Size of the rest of the chunk following this number.
|
||||
*/
|
||||
uint32_t chunk_size;
|
||||
/**
|
||||
* @brief Contains the letters "WAVE".
|
||||
*/
|
||||
uint32_t format;
|
||||
/**
|
||||
* @brief Contains the letters "fmt ".
|
||||
*/
|
||||
uint32_t subchunk1_id;
|
||||
/**
|
||||
* @brief 16 for PCM. This is the size of the rest of the Subchunk which follows this number.
|
||||
*/
|
||||
uint32_t subchunk1_size;
|
||||
/**
|
||||
* @brief PCM = 1 (i.e. Linear quantization). Values other than 1 indicate some form of compression.
|
||||
*/
|
||||
uint16_t audio_format;
|
||||
/**
|
||||
* @brief Mono = 1, Stereo = 2, etc.
|
||||
*/
|
||||
uint16_t num_channels;
|
||||
/**
|
||||
* @brief 8000, 44100, etc.
|
||||
*/
|
||||
uint32_t sample_rate;
|
||||
/**
|
||||
* @brief SampleRate * NumChannels * BitsPerSample/8
|
||||
*/
|
||||
uint32_t byte_rate;
|
||||
/**
|
||||
* @brief NumChannels * BitsPerSample/8
|
||||
*/
|
||||
uint16_t block_align;
|
||||
/**
|
||||
* @brief 8 bits = 8, 16 bits = 16, etc.
|
||||
*/
|
||||
uint16_t bits_per_sample;
|
||||
/**
|
||||
* @brief Contains the letters "data".
|
||||
*/
|
||||
uint32_t subchunk2_id;
|
||||
/**
|
||||
* @brief Number of bytes in the data.
|
||||
*/
|
||||
uint32_t subchunk2_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an CLASSD driver.
|
||||
*/
|
||||
typedef struct CLASSDDriver CLASSDDriver;
|
||||
|
||||
/**
|
||||
* @brief Type of a generic CLASSD callback.
|
||||
*/
|
||||
typedef void (*classdcb_t)(CLASSDDriver *classdp);
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Callback pointer.
|
||||
*/
|
||||
classdcb_t callback;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD left channel.
|
||||
*/
|
||||
uint32_t left;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD right channel.
|
||||
*/
|
||||
uint32_t right;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD left channel mute.
|
||||
*/
|
||||
uint32_t left_mute;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD right channel mute.
|
||||
*/
|
||||
uint32_t right_mute;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD PWM modulation type.
|
||||
*/
|
||||
uint32_t pwm_mode;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD Non-Overlapping.
|
||||
*/
|
||||
uint32_t non_overlap;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD Non-Overlapping value.
|
||||
*/
|
||||
uint32_t novrval;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD left channel attenuation.
|
||||
*/
|
||||
uint32_t attl;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD right channel attenuation.
|
||||
*/
|
||||
uint32_t attr;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD de-emphasis filter.
|
||||
*/
|
||||
uint32_t deemp;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD swap left right channel.
|
||||
*/
|
||||
uint32_t swap;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD sample frequency.
|
||||
*/
|
||||
uint32_t frame;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD EQ config.
|
||||
*/
|
||||
uint32_t eqcfg;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD mono signal.
|
||||
*/
|
||||
uint32_t mono;
|
||||
/**
|
||||
* @brief Configuration of the CLASSD mono mode.
|
||||
*/
|
||||
uint32_t mono_mode;
|
||||
} CLASSDConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an CLASSD driver.
|
||||
*/
|
||||
struct CLASSDDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
classdstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const CLASSDConfig *config;
|
||||
/**
|
||||
* @brief Pointer to the WDT registers block.
|
||||
*/
|
||||
Classd *classd;
|
||||
/**
|
||||
* @brief Transmit DMA stream.
|
||||
*/
|
||||
sama_dma_channel_t *dmatx;
|
||||
/**
|
||||
* @brief TX DMA mode bit mask.
|
||||
*/
|
||||
uint32_t txdmamode;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
extern CLASSDDriver CLASSDD0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void classdInit(void);
|
||||
void classdObjectInit(CLASSDDriver *classdp);
|
||||
void classdStart(CLASSDDriver *classdp, const CLASSDConfig *config);
|
||||
void classdStop(CLASSDDriver *classdp);
|
||||
void classdSetSampleFrame(CLASSDConfig *classdconfigp, uint8_t *music_file);
|
||||
void classdSendAudioI(CLASSDDriver *classdp, const void *txbuf);
|
||||
void classdSendAudio(CLASSDDriver *classdp, const void *txbuf);
|
||||
void classdMuteChannel(CLASSDDriver *classdp, bool left, bool right);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_CLASSD */
|
||||
|
||||
#endif /* SAMA_CLASSD_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,955 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_lcdc.c
|
||||
* @brief SAMA LCDC support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_LCDC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (SAMA_USE_LCDC) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* @brief NO CACHE attribute
|
||||
*/
|
||||
#if !defined(NO_CACHE)
|
||||
#define NO_CACHE __attribute__((section (".nocache")))
|
||||
#endif
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* @name Configuration Macros
|
||||
* @{
|
||||
*/
|
||||
/*
|
||||
* @brief Transfer Descriptor Fetch Enable
|
||||
*/
|
||||
#define LCDC_CTRL_DFETCH (0x1u << 0)
|
||||
/*
|
||||
* @brief Channel Enable Register
|
||||
*/
|
||||
#define LCDC_CHER_CHEN (0x1u << 0)
|
||||
/*
|
||||
* @brief Channel Disable Register
|
||||
*/
|
||||
#define LCDC_CHDR_CHDIS (0x1u << 0)
|
||||
/*
|
||||
* @brief Update Overlay Attributes Enable Register
|
||||
*/
|
||||
#define LCDC_CHER_UPDATEEN (0x1u << 1)
|
||||
/*
|
||||
* @brief Blender DMA Layer Enable
|
||||
*/
|
||||
#define LCDC_CFG_DMA (0x1u << 8)
|
||||
/*
|
||||
* @brief Blender Overlay Layer Enable
|
||||
*/
|
||||
#define LCDC_CFG_OVR (0x1u << 7)
|
||||
/*
|
||||
* @brief Pixel Stride
|
||||
*/
|
||||
#define LCDC_CFG_PSTRIDE_Pos 0
|
||||
#define LCDC_CFG_PSTRIDE_Msk (0xffffffffu << LCDC_CFG_PSTRIDE_Pos)
|
||||
#define LCDC_CFG_PSTRIDE(value) ((LCDC_CFG_PSTRIDE_Msk & ((value) << \
|
||||
LCDC_CFG_PSTRIDE_Pos)))
|
||||
/*
|
||||
* @brief Horizontal Stride
|
||||
*/
|
||||
#define LCDC_CFG_XSTRIDE_Pos 0
|
||||
#define LCDC_CFG_XSTRIDE_Msk (0xffffffffu << LCDC_CFG_XSTRIDE_Pos)
|
||||
#define LCDC_CFG_XSTRIDE(value) ((LCDC_CFG_XSTRIDE_Msk & ((value) << \
|
||||
LCDC_CFG_XSTRIDE_Pos)))
|
||||
/*
|
||||
* @brief Hardware Rotation Optimization Disable
|
||||
*/
|
||||
#define LCDC_CFG_ROTDIS (0x1u << 12)
|
||||
|
||||
/*
|
||||
* @brief Horizontal Window Position
|
||||
*/
|
||||
#define LCDC_CFG_XPOS_Pos 0
|
||||
#define LCDC_CFG_XPOS_Msk (0x7ffu << LCDC_CFG_XPOS_Pos)
|
||||
#define LCDC_CFG_XPOS(value) ((LCDC_CFG_XPOS_Msk & ((value) << LCDC_CFG_XPOS_Pos)))
|
||||
|
||||
/*
|
||||
* @brief Vertical Window Position
|
||||
*/
|
||||
#define LCDC_CFG_YPOS_Pos 16
|
||||
#define LCDC_CFG_YPOS_Msk (0x7ffu << LCDC_CFG_YPOS_Pos)
|
||||
#define LCDC_CFG_YPOS(value) ((LCDC_CFG_YPOS_Msk & ((value) << LCDC_CFG_YPOS_Pos)))
|
||||
|
||||
/*
|
||||
* @brief Horizontal Window Size
|
||||
*/
|
||||
#define LCDC_CFG_XSIZE_Pos 0
|
||||
#define LCDC_CFG_XSIZE_Msk (0x7ffu << LCDC_CFG_XSIZE_Pos)
|
||||
#define LCDC_CFG_XSIZE(value) ((LCDC_CFG_XSIZE_Msk & ((value) << LCDC_CFG_XSIZE_Pos)))
|
||||
|
||||
/*
|
||||
* @brief Vertical Window Size
|
||||
*/
|
||||
#define LCDC_CFG_YSIZE_Pos 16
|
||||
#define LCDC_CFG_YSIZE_Msk (0x7ffu << LCDC_CFG_YSIZE_Pos)
|
||||
#define LCDC_CFG_YSIZE(value) ((LCDC_CFG_YSIZE_Msk & ((value) << LCDC_CFG_YSIZE_Pos)))
|
||||
|
||||
/*
|
||||
* @brief Horizontal image Size in Memory
|
||||
*/
|
||||
#define LCDC_CFG_XMEMSIZE_Pos 0
|
||||
#define LCDC_CFG_XMEMSIZE_Msk (0x7ffu << LCDC_CFG_XMEMSIZE_Pos)
|
||||
#define LCDC_CFG_XMEMSIZE(value) ((LCDC_CFG_XMEMSIZE_Msk & ((value) << LCDC_CFG_XMEMSIZE_Pos)))
|
||||
|
||||
/*
|
||||
* @brief Vertical image Size in Memory
|
||||
*/
|
||||
#define LCDC_CFG_YMEMSIZE_Pos 16
|
||||
#define LCDC_CFG_YMEMSIZE_Msk (0x7ffu << LCDC_CFG_YMEMSIZE_Pos)
|
||||
#define LCDC_CFG_YMEMSIZE(value) ((LCDC_CFG_YMEMSIZE_Msk & ((value) << LCDC_CFG_YMEMSIZE_Pos)))
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
LCDCDriver LCDCD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief DMA Channel Descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Frame Buffer base address register.
|
||||
*/
|
||||
uint32_t addr;
|
||||
/**
|
||||
* @brief Transfer Control register.
|
||||
*/
|
||||
uint32_t ctrl;
|
||||
/**
|
||||
* @brief Next Descriptor Address register.
|
||||
*/
|
||||
uint32_t next;
|
||||
} lcdc_dma_descriptor_t;
|
||||
|
||||
/* Variable layer data */
|
||||
typedef struct {
|
||||
lcdc_dma_descriptor_t *dma_desc;
|
||||
lcdc_dma_descriptor_t *dma_u_desc;
|
||||
lcdc_dma_descriptor_t *dma_v_desc;
|
||||
void *buffer;
|
||||
uint8_t bpp;
|
||||
uint8_t num_colors;
|
||||
} layerdata_t;
|
||||
|
||||
/*
|
||||
* @brief Hardware info about the layers
|
||||
*/
|
||||
typedef struct {
|
||||
layerdata_t *data;
|
||||
bool stride_supported;
|
||||
/* regs: _ER, _DR, _SR, _IER, _IDR, _IMR, _ISR */
|
||||
volatile uint32_t *reg_enable;
|
||||
/* regs: blender */
|
||||
volatile uint32_t *reg_blender;
|
||||
/* _HEAD, _ADDRESS, _CONTROL, _NEXT */
|
||||
volatile uint32_t *reg_dma_head;
|
||||
/* _HEAD, _ADDRESS, _CONTROL, _NEXT */
|
||||
volatile uint32_t *reg_dma_u_head;
|
||||
/* _HEAD, _ADDRESS, _CONTROL, _NEXT */
|
||||
volatile uint32_t *reg_dma_v_head;
|
||||
/* regs: _CFG0, _CFG1 (RGB mode...) */
|
||||
volatile uint32_t *reg_cfg;
|
||||
/* X Y register, W H register */
|
||||
volatile uint32_t *reg_win;
|
||||
/* regs: stride */
|
||||
volatile uint32_t *reg_stride;
|
||||
/* regs: RGB Default, RGB Key, RGB Mask */
|
||||
volatile uint32_t *reg_color;
|
||||
/* regs: scale */
|
||||
volatile uint32_t *reg_scale;
|
||||
/* regs: CLUT */
|
||||
volatile uint32_t *reg_clut;
|
||||
} layerinfo_t;
|
||||
|
||||
/* Base Layer */
|
||||
static layerdata_t lcdd_base;
|
||||
/* OVR1 Layer */
|
||||
static layerdata_t lcdd_ovr1;
|
||||
/* OVR2 Layer */
|
||||
static layerdata_t lcdd_ovr2;
|
||||
/* HEO Layer */
|
||||
static layerdata_t lcdd_heo;
|
||||
/* HCC Layer */
|
||||
static layerdata_t lcdd_hcc;
|
||||
|
||||
/*
|
||||
* @brief DMA descriptor
|
||||
* @note The DMA Channel Descriptor (DSCR) must be aligned on a 64-bit boundary.
|
||||
*/
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for Base Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t base_dma_desc;
|
||||
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for OVR1 Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t ovr1_dma_desc;
|
||||
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for OVR2 Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t ovr2_dma_desc;
|
||||
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for HEO Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t heo_dma_desc;
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for HEO U-UV Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t heo_dma_u_desc;
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for HEO V Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t heo_dma_v_desc;
|
||||
|
||||
ALIGNED_VAR(8)
|
||||
/* DMA descriptor for HCC Layer */
|
||||
NO_CACHE static lcdc_dma_descriptor_t hcc_dma_desc;
|
||||
|
||||
/**
|
||||
* @brief Information about layers
|
||||
*/
|
||||
static const layerinfo_t lcdd_layers[] = {
|
||||
/* 0: LCDD_CONTROLLER */
|
||||
{
|
||||
.stride_supported = false,
|
||||
.reg_enable = &LCDC->LCDC_LCDEN,
|
||||
},
|
||||
|
||||
/* 1: LCDD_BASE */
|
||||
{
|
||||
.data = &lcdd_base,
|
||||
.stride_supported = false,
|
||||
.reg_enable = &LCDC->LCDC_BASECHER,
|
||||
.reg_blender = &LCDC->LCDC_BASECFG4,
|
||||
.reg_dma_head = &LCDC->LCDC_BASEHEAD,
|
||||
.reg_cfg = &LCDC->LCDC_BASECFG0,
|
||||
.reg_stride = &LCDC->LCDC_BASECFG2,
|
||||
.reg_color = &LCDC->LCDC_BASECFG3,
|
||||
.reg_clut = &LCDC->LCDC_BASECLUT[0]
|
||||
},
|
||||
|
||||
/* 2: LCDD_OVR1 */
|
||||
{
|
||||
.data = &lcdd_ovr1,
|
||||
.stride_supported = true,
|
||||
.reg_enable = &LCDC->LCDC_OVR1CHER,
|
||||
.reg_blender = &LCDC->LCDC_OVR1CFG9,
|
||||
.reg_dma_head = &LCDC->LCDC_OVR1HEAD,
|
||||
.reg_cfg = &LCDC->LCDC_OVR1CFG0,
|
||||
.reg_win = &LCDC->LCDC_OVR1CFG2,
|
||||
.reg_stride = &LCDC->LCDC_OVR1CFG4,
|
||||
.reg_color = &LCDC->LCDC_OVR1CFG6,
|
||||
.reg_clut = &LCDC->LCDC_OVR1CLUT[0],
|
||||
},
|
||||
|
||||
/* 3: LCDD_HEO */
|
||||
{
|
||||
.data = &lcdd_heo,
|
||||
.stride_supported = true,
|
||||
.reg_enable = &LCDC->LCDC_HEOCHER,
|
||||
.reg_blender = &LCDC->LCDC_HEOCFG12,
|
||||
.reg_dma_head = &LCDC->LCDC_HEOHEAD,
|
||||
.reg_dma_u_head = &LCDC->LCDC_HEOUHEAD,
|
||||
.reg_dma_v_head = &LCDC->LCDC_HEOVHEAD,
|
||||
.reg_cfg = &LCDC->LCDC_HEOCFG0,
|
||||
.reg_win = &LCDC->LCDC_HEOCFG2,
|
||||
.reg_stride = &LCDC->LCDC_HEOCFG5,
|
||||
.reg_color = &LCDC->LCDC_HEOCFG9,
|
||||
.reg_scale = &LCDC->LCDC_HEOCFG13,
|
||||
.reg_clut = &LCDC->LCDC_HEOCLUT[0],
|
||||
},
|
||||
|
||||
/* 4: LCDD_OVR2 */
|
||||
{
|
||||
.data = &lcdd_ovr2,
|
||||
.stride_supported = true,
|
||||
.reg_enable = &LCDC->LCDC_OVR2CHER,
|
||||
.reg_blender = &LCDC->LCDC_OVR2CFG9,
|
||||
.reg_dma_head = &LCDC->LCDC_OVR2HEAD,
|
||||
.reg_cfg = &LCDC->LCDC_OVR2CFG0,
|
||||
.reg_win = &LCDC->LCDC_OVR2CFG2,
|
||||
.reg_stride = &LCDC->LCDC_OVR2CFG4,
|
||||
.reg_color = &LCDC->LCDC_OVR2CFG6,
|
||||
.reg_clut = &LCDC->LCDC_OVR2CLUT[0],
|
||||
}
|
||||
,
|
||||
/* 5: N/A */
|
||||
{
|
||||
.data = NULL,
|
||||
},
|
||||
|
||||
/* 6: LCDD_CUR */
|
||||
{
|
||||
.data = &lcdd_hcc,
|
||||
.stride_supported = false,
|
||||
},
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* @brief Clear DMA channel descriptor
|
||||
*
|
||||
* @param[in] descp pointer to lcdc_dma_descriptor
|
||||
* @param[in] dma_regp pointer to LCDC leyer register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void clear_dma_desc(lcdc_dma_descriptor_t *descp, volatile uint32_t *dma_regp) {
|
||||
/* Modify descriptor */
|
||||
if (descp) {
|
||||
descp->ctrl &= ~LCDC_CTRL_DFETCH;
|
||||
descp->next = (uint32_t)descp;
|
||||
//cacheCleanRegion(descp, sizeof(lcdc_dma_descriptor_t));
|
||||
}
|
||||
|
||||
/* Modify registers */
|
||||
dma_regp[2] &= ~LCDC_CTRL_DFETCH;
|
||||
dma_regp[3] = (uint32_t)descp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computing scaling factor.
|
||||
*
|
||||
* @param[in] layerp pointer to a layerinfo_t struct
|
||||
* @param[out] xfactorp pointer to xfactor scaling factor
|
||||
* @param[out] yfactorp pointer to yfactor scaling factor
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void compute_scaling_factors(const layerinfo_t *layerp,
|
||||
uint16_t* xfactorp, uint16_t* yfactorp)
|
||||
{
|
||||
uint16_t xmemsize, ymemsize;
|
||||
uint16_t xsize, ysize;
|
||||
|
||||
#ifdef LCDC_HEOCFG41_XPHIDEF
|
||||
uint16_t xfactor_1st, yfactor_1st;
|
||||
#endif
|
||||
|
||||
xmemsize = (layerp->reg_win[2] & LCDC_CFG_XMEMSIZE_Msk) >> LCDC_CFG_XMEMSIZE_Pos;
|
||||
ymemsize = (layerp->reg_win[2] & LCDC_CFG_YMEMSIZE_Msk) >> LCDC_CFG_YMEMSIZE_Pos;
|
||||
xsize = (layerp->reg_win[1] & LCDC_CFG_XSIZE_Msk) >> LCDC_CFG_XSIZE_Pos;
|
||||
ysize = (layerp->reg_win[1] & LCDC_CFG_YSIZE_Msk) >> LCDC_CFG_YSIZE_Pos;
|
||||
|
||||
#ifdef LCDC_HEOCFG41_XPHIDEF
|
||||
/* we assume that XPHIDEF & YPHIDEF are 0 */
|
||||
xfactor_1st = (2048 * xmemsize / xsize) + 1;
|
||||
yfactor_1st = (2048 * ymemsize / ysize) + 1;
|
||||
|
||||
if ((xfactor_1st * xsize / 2048) > xmemsize)
|
||||
*xfactorp = xfactor_1st - 1;
|
||||
else
|
||||
*xfactorp = xfactor_1st;
|
||||
|
||||
if ((yfactor_1st * ysize / 2048) > ymemsize)
|
||||
*yfactorp = yfactor_1st - 1;
|
||||
else
|
||||
*yfactorp = yfactor_1st;
|
||||
#else
|
||||
*xfactorp = 1024 * (xmemsize + 1) / (xsize + 1);
|
||||
*yfactorp = 1024 * (ymemsize + 1) / (ysize + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures LCDC layers according to configuration struct.
|
||||
*
|
||||
* @param[in] listp pointer to a LCDCLayerConfig array
|
||||
* @param[in] length length of array
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void layer_config(LCDCLayerConfig *listp, size_t length) {
|
||||
uint8_t i;
|
||||
uint8_t bpp_bit;
|
||||
uint8_t bpp;
|
||||
uint32_t index;
|
||||
|
||||
uint32_t padding = 0;
|
||||
uint32_t src_w, src_h, img_w, img_h;
|
||||
uint32_t bits_per_row, bytes_per_row;
|
||||
|
||||
LCDCLayerConfig *layerp;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
index = listp[i].layer_id;
|
||||
|
||||
osalDbgAssert((index != LCDD_CONTROLLER) || (index != LCDD_CUR), "This is not a real layer");
|
||||
|
||||
layerp = &listp[i];
|
||||
uint16_t w, h, x, y;
|
||||
|
||||
bpp = layerp->bpp;
|
||||
w = layerp->width;
|
||||
h = layerp->height;
|
||||
x = layerp->x_pos;
|
||||
y = layerp->y_pos;
|
||||
img_w = layerp->w_img;
|
||||
img_h = layerp->h_img;
|
||||
|
||||
/* Bpp settings */
|
||||
lcdd_layers[index].reg_cfg[1] = layerp->bpp;
|
||||
bpp = bpp >> 4;
|
||||
|
||||
if (bpp == 1 || bpp < 5) {
|
||||
bpp_bit = 16;
|
||||
}
|
||||
else if (bpp == 5 || bpp == 6) {
|
||||
bpp_bit = 18;
|
||||
}
|
||||
else if (bpp == 7 || bpp == 8) {
|
||||
bpp_bit = 19;
|
||||
}
|
||||
else if (bpp == 9 || bpp == 10) {
|
||||
bpp_bit = 24;
|
||||
}
|
||||
else if (bpp == 11) {
|
||||
bpp_bit = 25;
|
||||
}
|
||||
else if (bpp == 12 || bpp == 13) {
|
||||
bpp_bit = 32;
|
||||
}
|
||||
else {
|
||||
bpp_bit = 12;
|
||||
}
|
||||
|
||||
/* Set display buffer & mode */
|
||||
bits_per_row = img_w * bpp_bit;
|
||||
bytes_per_row = bits_per_row >> 3;
|
||||
|
||||
if (bits_per_row & 0x7) {
|
||||
bytes_per_row++;
|
||||
}
|
||||
if (bytes_per_row & 0x3) {
|
||||
padding = 4 - (bytes_per_row & 0x3);
|
||||
}
|
||||
/* No rotation optimization */
|
||||
lcdd_layers[index].reg_cfg[0] |= LCDC_CFG_ROTDIS;
|
||||
|
||||
/* Configure PSTRIDE if supported */
|
||||
if (lcdd_layers[index].stride_supported)
|
||||
lcdd_layers[index].reg_stride[1] = LCDC_CFG_PSTRIDE(0);
|
||||
/* Configure XSTRIDE if supported */
|
||||
lcdd_layers[index].reg_stride[0] = LCDC_CFG_XSTRIDE(padding);
|
||||
|
||||
/* Set window & position */
|
||||
if (lcdd_layers[index].reg_win) {
|
||||
|
||||
/* Re - calculate to eliminate hardware overflow */
|
||||
if (x + w > LCDCD0.config->width) {
|
||||
w = LCDCD0.config->width - x;
|
||||
}
|
||||
if (y + h > LCDCD0.config->height) {
|
||||
h = LCDCD0.config->height - y;
|
||||
}
|
||||
|
||||
if (w == 0)
|
||||
w++;
|
||||
|
||||
if (h == 0)
|
||||
h++;
|
||||
|
||||
lcdd_layers[index].reg_win[0] = LCDC_CFG_XPOS(x) | LCDC_CFG_YPOS(y);
|
||||
lcdd_layers[index].reg_win[1] = LCDC_CFG_XSIZE(w - 1) | LCDC_CFG_YSIZE(h - 1);
|
||||
}
|
||||
|
||||
/* Scaling setup, only HEO layer has scaling register */
|
||||
if (lcdd_layers[index].reg_win && lcdd_layers[index].reg_scale) {
|
||||
src_w = img_w;
|
||||
src_h = img_h;
|
||||
|
||||
lcdd_layers[index].reg_win[2] = LCDC_CFG_XMEMSIZE(src_w - 1) |
|
||||
LCDC_CFG_YMEMSIZE(src_h - 1);
|
||||
/* Scaled */
|
||||
if (w != src_w || h != src_h) {
|
||||
uint16_t scale_w, scale_h;
|
||||
compute_scaling_factors(&lcdd_layers[index], &scale_w, &scale_h);
|
||||
lcdd_layers[index].reg_scale[0] = LCDC_HEOCFG13_YFACTOR(scale_h) |
|
||||
LCDC_HEOCFG13_XFACTOR(scale_w) |
|
||||
LCDC_HEOCFG13_SCALEN;
|
||||
}
|
||||
/* Disable scaling */
|
||||
else {
|
||||
lcdd_layers[index].reg_scale[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure Descriptor */
|
||||
lcdd_layers[index].data->dma_desc->addr = (uint32_t)layerp->buffer;
|
||||
lcdd_layers[index].data->dma_desc->ctrl = LCDC_CTRL_DFETCH;
|
||||
lcdd_layers[index].data->dma_desc->next = (uint32_t)lcdd_layers[index].data->dma_desc;
|
||||
|
||||
lcdd_layers[index].reg_dma_head[1] = (uint32_t)lcdd_layers[index].data->dma_desc->addr;
|
||||
lcdd_layers[index].reg_dma_head[2] = LCDC_CTRL_DFETCH;
|
||||
lcdd_layers[index].reg_dma_head[3] = (uint32_t)lcdd_layers[index].data->dma_desc;
|
||||
|
||||
/* Configure layer */
|
||||
lcdd_layers[index].reg_enable[0] = LCDC_CHER_UPDATEEN;
|
||||
lcdd_layers[index].reg_blender[0] |= LCDC_CFG_DMA | LCDC_CFG_OVR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable Display.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*/
|
||||
static void lcdc_on(LCDCDriver *lcdcp) {
|
||||
|
||||
uint32_t pixel_clock = lcdcp->config->framerate;
|
||||
pixel_clock *= lcdcp->config->timing_hpw + lcdcp->config->timing_hbp +
|
||||
lcdcp->config->width + lcdcp->config->timing_hfp;
|
||||
pixel_clock *= lcdcp->config->timing_vpw + lcdcp->config->timing_vbp +
|
||||
lcdcp->config->height + lcdcp->config->timing_vfp;
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
/* Configure LCD timing parameters, signal polarity and clock period. */
|
||||
if( LCDC->LCDC_LCDCFG0 & LCDC_LCDCFG0_CLKSEL) {
|
||||
LCDC->LCDC_LCDCFG0 = LCDC_LCDCFG0_CLKDIV((SAMA_MCK * 2) / pixel_clock - 2) |
|
||||
LCDC_LCDCFG0_CGDISHEO | LCDC_LCDCFG0_CGDISOVR1 |
|
||||
LCDC_LCDCFG0_CGDISOVR2 | LCDC_LCDCFG0_CGDISBASE |
|
||||
LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CLKSEL;
|
||||
}
|
||||
else {
|
||||
LCDC->LCDC_LCDCFG0 = LCDC_LCDCFG0_CLKDIV(SAMA_MCK / pixel_clock - 2) |
|
||||
LCDC_LCDCFG0_CGDISBASE | LCDC_LCDCFG0_CGDISHEO |
|
||||
LCDC_LCDCFG0_CLKPWMSEL;
|
||||
}
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG1 = LCDC_LCDCFG1_VSPW(lcdcp->config->timing_vpw - 1) |
|
||||
LCDC_LCDCFG1_HSPW(lcdcp->config->timing_hpw - 1);
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG2 = LCDC_LCDCFG2_VBPW(lcdcp->config->timing_vbp) |
|
||||
LCDC_LCDCFG2_VFPW(lcdcp->config->timing_vfp - 1);
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG3 = LCDC_LCDCFG3_HBPW(lcdcp->config->timing_hbp - 1) |
|
||||
LCDC_LCDCFG3_HFPW(lcdcp->config->timing_hfp - 1);
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG4 = LCDC_LCDCFG4_RPF(lcdcp->config->height - 1) |
|
||||
LCDC_LCDCFG4_PPL(lcdcp->config->width - 1);
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG5 = LCDC_LCDCFG5_GUARDTIME(30) | LCDC_LCDCFG5_MODE_OUTPUT_24BPP |
|
||||
LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS | LCDC_LCDCFG5_VSPOL |
|
||||
LCDC_LCDCFG5_HSPOL;
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
LCDC->LCDC_LCDCFG6 = LCDC_LCDCFG6_PWMCVAL(0xF0) | LCDC_LCDCFG6_PWMPOL |
|
||||
LCDC_LCDCFG6_PWMPS(6);
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
|
||||
/* Enable the Pixel Clock. */
|
||||
LCDC->LCDC_LCDEN = LCDC_LCDEN_CLKEN;
|
||||
|
||||
/* Poll to check that clock is running. */
|
||||
while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_CLKSTS));
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
/* Enable Horizontal and Vertical Synchronization. */
|
||||
LCDC->LCDC_LCDEN = LCDC_LCDEN_SYNCEN;
|
||||
/* Poll to check that the synchronization is up. */
|
||||
while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_LCDSTS));
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
/* Enable the display power signal. */
|
||||
LCDC->LCDC_LCDEN = LCDC_LCDEN_DISPEN;
|
||||
/* Poll to check that the power signal is activated. */
|
||||
while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_DISPSTS));
|
||||
|
||||
/* Wait for clock domain synchronization to be complete. */
|
||||
while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS));
|
||||
|
||||
/* Enable backlight */
|
||||
LCDC->LCDC_LCDEN = LCDC_LCDEN_PWMEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable Display.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*/
|
||||
static void lcdc_off(void) {
|
||||
|
||||
/* Disable all DMA channel descriptors */
|
||||
clear_dma_desc(&base_dma_desc, &LCDC->LCDC_BASEADDR);
|
||||
clear_dma_desc(&ovr1_dma_desc, &LCDC->LCDC_OVR1ADDR);
|
||||
clear_dma_desc(&ovr2_dma_desc, &LCDC->LCDC_OVR2ADDR);
|
||||
clear_dma_desc(&heo_dma_desc, &LCDC->LCDC_HEOADDR);
|
||||
clear_dma_desc(&heo_dma_u_desc, &LCDC->LCDC_HEOUADDR);
|
||||
clear_dma_desc(&heo_dma_v_desc, &LCDC->LCDC_HEOVADDR);
|
||||
|
||||
/* Disable DMA channels */
|
||||
LCDC->LCDC_BASECHDR = LCDC_BASECHDR_CHDIS;
|
||||
LCDC->LCDC_OVR1CHDR = LCDC_OVR1CHDR_CHDIS;
|
||||
LCDC->LCDC_OVR2CHDR = LCDC_OVR2CHDR_CHDIS;
|
||||
LCDC->LCDC_HEOCHDR = LCDC_HEOCHDR_CHDIS;
|
||||
LCDC->LCDC_BASECFG4 = 0;
|
||||
|
||||
/* Poll CHSR until the channel is successfully disabled. */
|
||||
while (LCDC->LCDC_BASECHSR & LCDC_BASECHSR_CHSR);
|
||||
while (LCDC->LCDC_OVR1CHSR & LCDC_OVR1CHSR_CHSR);
|
||||
while (LCDC->LCDC_OVR2CHSR & LCDC_OVR1CHSR_CHSR);
|
||||
while (LCDC->LCDC_HEOCHSR & LCDC_HEOCHSR_CHSR);
|
||||
|
||||
/* Disable backlight */
|
||||
LCDC->LCDC_LCDDIS = LCDC_LCDDIS_PWMDIS;
|
||||
/* Poll PWMSTS: field of the LCDC_LCDSR register to verify that the PWM
|
||||
is no activated. */
|
||||
while (LCDC->LCDC_LCDSR & LCDC_LCDSR_PWMSTS);
|
||||
|
||||
/* Disable the DISP signal. */
|
||||
LCDC->LCDC_LCDDIS = LCDC_LCDDIS_DISPDIS;
|
||||
/* Poll DISPSTS field of the LCDC_LCDSR register to verify that the DISP
|
||||
is no longer activated. */
|
||||
while (LCDC->LCDC_LCDSR & LCDC_LCDSR_DISPSTS);
|
||||
|
||||
/* Disable the hsync and vsync signals. */
|
||||
LCDC->LCDC_LCDDIS = LCDC_LCDDIS_SYNCDIS;
|
||||
/* Poll LCDSTS field of the LCDC_LCDSR register to check that the
|
||||
synchronization is off. */
|
||||
while (LCDC->LCDC_LCDSR & LCDC_LCDSR_LCDSTS);
|
||||
|
||||
/* Disable the Pixel clock. */
|
||||
LCDC->LCDC_LCDDIS = LCDC_LCDDIS_CLKDIS;
|
||||
/* Poll CLKSTS field of the LCDC_LCDSR register to check that Pixel Clock
|
||||
is disabled. */
|
||||
while (LCDC->LCDC_LCDSR & LCDC_LCDSR_CLKSTS);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level LCDC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void lcdc_lld_init(void) {
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX0, ID_LCDC, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/* Driver initialization.*/
|
||||
lcdcObjectInit(&LCDCD0);
|
||||
LCDCD0.lcdc = LCDC;
|
||||
|
||||
/* Reset layer information */
|
||||
lcdd_base.bpp = 0;
|
||||
lcdd_base.buffer = NULL;
|
||||
lcdd_base.dma_desc = &base_dma_desc;
|
||||
|
||||
lcdd_ovr1.bpp = 0;
|
||||
lcdd_ovr1.buffer = NULL;
|
||||
lcdd_ovr1.dma_desc = &ovr1_dma_desc;
|
||||
|
||||
lcdd_ovr2.bpp = 0;
|
||||
lcdd_ovr2.buffer = NULL;
|
||||
lcdd_ovr2.dma_desc = &ovr2_dma_desc;
|
||||
|
||||
lcdd_heo.bpp = 0;
|
||||
lcdd_heo.buffer = NULL;
|
||||
lcdd_heo.dma_desc = &heo_dma_desc;
|
||||
lcdd_heo.dma_u_desc = &heo_dma_u_desc;
|
||||
lcdd_heo.dma_v_desc = &heo_dma_v_desc;
|
||||
|
||||
lcdd_hcc.bpp = 0;
|
||||
lcdd_base.buffer = NULL;
|
||||
lcdd_hcc.dma_desc = &hcc_dma_desc;
|
||||
|
||||
/* Disable LCD controller */
|
||||
lcdc_off();
|
||||
|
||||
/* Timing Engine Configuration */
|
||||
|
||||
/* Disable interrupt */
|
||||
LCDC->LCDC_LCDIDR = 0xFFFFFFFF;
|
||||
|
||||
/* Base */
|
||||
LCDC->LCDC_BASECFG0 = LCDC_BASECFG0_DLBO | LCDC_BASECFG0_BLEN_AHB_INCR16;
|
||||
|
||||
/* Overlay 1, GA 0xFF */
|
||||
LCDC->LCDC_OVR1CFG0 = LCDC_OVR1CFG0_DLBO | LCDC_OVR1CFG0_BLEN_AHB_BLEN_INCR16 |
|
||||
LCDC_OVR1CFG0_ROTDIS;
|
||||
|
||||
LCDC->LCDC_OVR1CFG9 = LCDC_OVR1CFG9_GA(0xFF) | LCDC_OVR1CFG9_GAEN;
|
||||
|
||||
/* Overlay 2, GA 0xFF */
|
||||
LCDC->LCDC_OVR2CFG0 = LCDC_OVR2CFG0_DLBO | LCDC_OVR2CFG0_BLEN_AHB_INCR16 |
|
||||
LCDC_OVR2CFG0_ROTDIS;
|
||||
LCDC->LCDC_OVR2CFG9 = LCDC_OVR2CFG9_GA(0xFF) | LCDC_OVR2CFG9_GAEN;
|
||||
|
||||
/* High End Overlay, GA 0xFF */
|
||||
LCDC->LCDC_HEOCFG0 = LCDC_HEOCFG0_DLBO | LCDC_HEOCFG0_BLEN_AHB_BLEN_INCR16 |
|
||||
LCDC_HEOCFG0_ROTDIS;
|
||||
LCDC->LCDC_HEOCFG12 = LCDC_HEOCFG12_GA(0xFF) | LCDC_HEOCFG12_GAEN;
|
||||
LCDC->LCDC_HEOCFG14 = LCDC_HEOCFG14_CSCRY(0x94) | LCDC_HEOCFG14_CSCRU(0xCC) |
|
||||
LCDC_HEOCFG14_CSCRV(0) | LCDC_HEOCFG14_CSCYOFF;
|
||||
LCDC->LCDC_HEOCFG15 = LCDC_HEOCFG15_CSCGY(0x94) | LCDC_HEOCFG15_CSCGU(0x387) |
|
||||
LCDC_HEOCFG15_CSCGV(0x3CD) | LCDC_HEOCFG15_CSCUOFF;
|
||||
LCDC->LCDC_HEOCFG16 = LCDC_HEOCFG16_CSCBY(0x94)| LCDC_HEOCFG16_CSCBU(0) |
|
||||
LCDC_HEOCFG16_CSCBV(0x102) | LCDC_HEOCFG16_CSCVOFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the LCDC peripheral.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void lcdc_lld_start(LCDCDriver *lcdcp) {
|
||||
|
||||
/* Enable the LCDC peripheral clock. */
|
||||
pmcEnableLCDC();
|
||||
|
||||
/* Configure overlays */
|
||||
layer_config(lcdcp->config->listp, lcdcp->config->length);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the LCDC peripheral.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void lcdc_lld_stop(LCDCDriver *lcdcp) {
|
||||
|
||||
if (lcdcp->state == LCDC_READY) {
|
||||
|
||||
/* Disable display. */
|
||||
lcdc_off();
|
||||
|
||||
/* Disable the LCDC clock. */
|
||||
pmcDisableLCDC();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Initializes the standard part of a @p LCDCDriver structure.
|
||||
*
|
||||
* @param[out] lcdcp pointer to a @p LCDCDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void lcdcObjectInit(LCDCDriver *lcdcp) {
|
||||
lcdcp->state = LCDC_STOP;
|
||||
lcdcp->config = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCDC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void lcdcInit(void) {
|
||||
|
||||
lcdc_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the LCDC peripheral.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
* @param[in] configp pointer to the LCDCConfig struct
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void lcdcStart(LCDCDriver *lcdcp, const LCDCConfig *configp) {
|
||||
|
||||
osalDbgCheck(lcdcp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((lcdcp->state == LCDC_STOP) , "invalid state");
|
||||
lcdcp->config = configp;
|
||||
lcdc_lld_start(lcdcp);
|
||||
lcdcp->state = LCDC_READY;
|
||||
osalSysUnlock();
|
||||
|
||||
/* Enable display. */
|
||||
lcdc_on(lcdcp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the LCDC peripheral.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void lcdcStop(LCDCDriver *lcdcp) {
|
||||
|
||||
osalDbgCheck(lcdcp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((lcdcp->state == LCDC_READY), "invalid state");
|
||||
|
||||
lcdc_lld_stop(lcdcp);
|
||||
lcdcp->state = LCDC_STOP;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
void lcdcShowLayer(LCDCDriver *lcdcp, uint8_t id, bool enable) {
|
||||
(void)lcdcp;
|
||||
|
||||
if(enable) {
|
||||
lcdd_layers[id].reg_enable[0] = LCDC_CHER_CHEN;
|
||||
}
|
||||
else {
|
||||
lcdd_layers[id].reg_enable[1] = LCDC_CHDR_CHDIS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief brief Set the backlight of the LCD.
|
||||
*
|
||||
* param[in] level Backlight brightness level [1..255],
|
||||
* 255 means maximum brightness.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void lcdcSetBacklight(uint32_t level) {
|
||||
uint32_t cfg = LCDC->LCDC_LCDCFG6 & ~LCDC_LCDCFG6_PWMCVAL_Msk;
|
||||
LCDC->LCDC_LCDCFG6 = cfg | LCDC_LCDCFG6_PWMCVAL(level);
|
||||
}
|
||||
|
||||
#if (TRUE == LCDC_USE_MUTUAL_EXCLUSION)
|
||||
|
||||
/**
|
||||
* @brief Gains exclusive access to the LCDC module.
|
||||
* @details This function tries to gain ownership to the LCDC module, if the
|
||||
* module is already being used then the invoking thread is queued.
|
||||
* @pre In order to use this function the option
|
||||
* @p LCDC_USE_MUTUAL_EXCLUSION must be enabled.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
void lcdcAcquireBusS(LCDCDriver *lcdcp) {
|
||||
|
||||
osalDbgCheckClassS();
|
||||
osalDbgCheck(lcdcp == &LCDCD0);
|
||||
|
||||
#if (TRUE == CH_CFG_USE_MUTEXES)
|
||||
chMtxLockS(&lcdcp->lock);
|
||||
#else
|
||||
chSemWaitS(&lcdcp->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gains exclusive access to the LCDC module.
|
||||
* @details This function tries to gain ownership to the LTDC module, if the
|
||||
* module is already being used then the invoking thread is queued.
|
||||
* @pre In order to use this function the option
|
||||
* @p LCDC_USE_MUTUAL_EXCLUSION must be enabled.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void lcdcAcquireBus(LCDCDriver *lcdcp) {
|
||||
|
||||
osalSysLock();
|
||||
lcdcAcquireBusS(lcdcp);
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases exclusive access to the LCDC module.
|
||||
* @pre In order to use this function the option
|
||||
* @p LCDC_USE_MUTUAL_EXCLUSION must be enabled.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
void lcdcReleaseBusS(LCDCDriver *lcdcp) {
|
||||
|
||||
osalDbgCheckClassS();
|
||||
osalDbgCheck(lcdcp == &LCDCD0);
|
||||
|
||||
#if (TRUE == CH_CFG_USE_MUTEXES)
|
||||
chMtxUnlockS(&lcdcp->lock);
|
||||
#else
|
||||
chSemSignalI(&lcdcp->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases exclusive access to the LCDC module.
|
||||
* @pre In order to use this function the option
|
||||
* @p LCDC_USE_MUTUAL_EXCLUSION must be enabled.
|
||||
*
|
||||
* @param[in] lcdcp pointer to the @p LCDCDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void lcdcReleaseBus(LCDCDriver *lcdcp) {
|
||||
|
||||
osalSysLock();
|
||||
lcdcReleaseBusS(lcdcp);
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
#endif /* LCDC_USE_MUTUAL_EXCLUSION */
|
||||
|
||||
#endif /* SAMA_USE_LCDC == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_lcdc.h
|
||||
* @brief SAMA LCDC support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_LCDC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_LCDC_LLD_H
|
||||
#define SAMA_LCDC_LLD_H
|
||||
|
||||
/**
|
||||
* @brief Using the LCDC driver.
|
||||
*/
|
||||
#if !defined(SAMA_USE_LCDC) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_LCDC FALSE
|
||||
#endif
|
||||
|
||||
#if (SAMA_USE_LCDC) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name LCDC ID LAYERS
|
||||
* @{
|
||||
*/
|
||||
/* LCD controller ID, no display, configuration ONLY */
|
||||
#define LCDD_CONTROLLER 0
|
||||
|
||||
/* LCD base layer, display fixed size image */
|
||||
#define LCDD_BASE 1
|
||||
|
||||
/* LCD Overlay 1 */
|
||||
#define LCDD_OVR1 2
|
||||
|
||||
/* LCD Overlay 2 */
|
||||
#define LCDD_OVR2 4
|
||||
|
||||
/* LCD HighEndOverlay, support resize */
|
||||
#define LCDD_HEO 3
|
||||
|
||||
/* LCD Cursor, max size 128x128 */
|
||||
#define LCDD_CUR 6
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name BPP MODE
|
||||
* @{
|
||||
*/
|
||||
#define LCDC_CFG_RGBMODE_12BPP_RGB_444 (0x0u << 4)
|
||||
#define LCDC_CFG_RGBMODE_16BPP_ARGB_4444 (0x1u << 4)
|
||||
#define LCDC_CFG_RGBMODE_16BPP_RGBA_4444 (0x2u << 4)
|
||||
#define LCDC_CFG_RGBMODE_16BPP_RGB_565 (0x3u << 4)
|
||||
#define LCDC_CFG_RGBMODE_16BPP_TRGB_1555 (0x4u << 4)
|
||||
#define LCDC_CFG_RGBMODE_18BPP_RGB_666 (0x5u << 4)
|
||||
#define LCDC_CFG_RGBMODE_18BPP_RGB_666PACKED (0x6u << 4)
|
||||
#define LCDC_CFG_RGBMODE_19BPP_TRGB_1666 (0x7u << 4)
|
||||
#define LCDC_CFG_RGBMODE_19BPP_TRGB_PACKED (0x8u << 4)
|
||||
#define LCDC_CFG_RGBMODE_24BPP_RGB_888 (0x9u << 4)
|
||||
#define LCDC_CFG_RGBMODE_24BPP_RGB_888_PACKED (0xAu << 4)
|
||||
#define LCDC_CFG_RGBMODE_25BPP_TRGB_1888 (0xBu << 4)
|
||||
#define LCDC_CFG_RGBMODE_32BPP_ARGB_8888 (0xCu << 4)
|
||||
#define LCDC_CFG_RGBMODE_32BPP_RGBA_8888 (0xDu << 4)
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief LCDC_USE_WAIT.
|
||||
*/
|
||||
#if !defined(LCDC_USE_WAIT) || defined(__DOXYGEN__)
|
||||
#define LCDC_USE_WAIT FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LCDC_USE_MUTUAL_EXCLUSION.
|
||||
*/
|
||||
#if !defined(LCDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||
#define LCDC_USE_MUTUAL_EXCLUSION FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
LCDC_UNINIT = 0, /**< Not initialized.*/
|
||||
LCDC_STOP = 1, /**< Stopped.*/
|
||||
LCDC_READY = 2, /**< Ready.*/
|
||||
LCDC_ACTIVE = 3, /**< Executing commands.*/
|
||||
} lcdcstate_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an LCDC driver.
|
||||
*/
|
||||
typedef struct LCDCDriver LCDCDriver;
|
||||
|
||||
/**
|
||||
* @brief LCD display layer information.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Display image buffer.
|
||||
*/
|
||||
void *buffer;
|
||||
/**
|
||||
* @brief Display image width.
|
||||
*/
|
||||
uint16_t width;
|
||||
/**
|
||||
* @brief Display image height.
|
||||
*/
|
||||
uint16_t height;
|
||||
/**
|
||||
* @brief Display image x position.
|
||||
*/
|
||||
uint16_t x_pos;
|
||||
/**
|
||||
* @brief Display image y_pos.
|
||||
*/
|
||||
uint16_t y_pos;
|
||||
/**
|
||||
* @brief Horizontal image Size in Memory.
|
||||
*/
|
||||
uint16_t w_img;
|
||||
/**
|
||||
* @brief Vertical image Size in Memory.
|
||||
*/
|
||||
uint16_t h_img;
|
||||
/**
|
||||
* @brief BPP mode.
|
||||
*/
|
||||
uint8_t bpp;
|
||||
/**
|
||||
* @brief Layer ID.
|
||||
*/
|
||||
uint8_t layer_id;
|
||||
} LCDCLayerConfig;
|
||||
|
||||
/**
|
||||
* @brief Driver LCD configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Display image width.
|
||||
*/
|
||||
uint16_t width;
|
||||
/**
|
||||
* @brief Display image height.
|
||||
*/
|
||||
uint16_t height;
|
||||
/**
|
||||
* @brief Frame rate in Hz.
|
||||
*/
|
||||
uint8_t framerate;
|
||||
/**
|
||||
* @brief Vertical front porch in number of lines.
|
||||
*/
|
||||
uint8_t timing_vfp;
|
||||
/**
|
||||
* @brief Vertical back porch in number of lines.
|
||||
*/
|
||||
uint8_t timing_vbp;
|
||||
/**
|
||||
* @brief Vertical pulse width in number of lines.
|
||||
*/
|
||||
uint8_t timing_vpw;
|
||||
/**
|
||||
* @brief Horizontal front porch in LCDDOTCLK cycles.
|
||||
*/
|
||||
uint8_t timing_hfp;
|
||||
/**
|
||||
* @brief Horizontal back porch in LCDDOTCLK cycles.
|
||||
*/
|
||||
uint8_t timing_hbp;
|
||||
/**
|
||||
* @brief Horizontal pulse width in LCDDOTCLK cycles.
|
||||
*/
|
||||
uint8_t timing_hpw;
|
||||
/**
|
||||
* @brief lenght of LCDCLayerConfig array
|
||||
* @note Number of layers to configure
|
||||
*/
|
||||
size_t length;
|
||||
/**
|
||||
* @brief pointer to LCDCLayerConfig array
|
||||
*/
|
||||
LCDCLayerConfig *listp;
|
||||
} LCDCConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an LCDC driver.
|
||||
*/
|
||||
struct LCDCDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
lcdcstate_t state;
|
||||
/**
|
||||
* @brief Current configuration lcd data.
|
||||
*/
|
||||
const LCDCConfig *config;
|
||||
/**
|
||||
* @brief Pointer to the LCDC registers block.
|
||||
*/
|
||||
Lcdc *lcdc;
|
||||
/* Multithreading stuff.*/
|
||||
#if (LCDC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
|
||||
thread_t *thread;
|
||||
#endif /* LCDC_USE_WAIT */
|
||||
#if (LCDC_USE_MUTUAL_EXCLUSION == TRUE)
|
||||
#if (CH_CFG_USE_MUTEXES == TRUE)
|
||||
mutex_t lock;
|
||||
#elif (CH_CFG_USE_SEMAPHORES == TRUE)
|
||||
semaphore_t lock;
|
||||
#endif
|
||||
#endif /* LCDC_USE_MUTUAL_EXCLUSION */
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern LCDCDriver LCDCD0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void lcdcObjectInit(LCDCDriver *lcdcp);
|
||||
void lcdcInit(void);
|
||||
void lcdcStart(LCDCDriver *lcdcp, const LCDCConfig *configp);
|
||||
void lcdcStop(LCDCDriver *lcdcp);
|
||||
void lcdcShowLayer(LCDCDriver *lcdcp, uint8_t id, bool enable);
|
||||
void lcdcSetBacklight(uint32_t level);
|
||||
#if (LCDC_USE_MUTUAL_EXCLUSION)
|
||||
void lcdcAcquireBusS(LCDCDriver *lcdcp);
|
||||
void lcdcAcquireBus(LCDCDriver *lcdcp);
|
||||
void lcdcReleaseBusS(LCDCDriver *lcdcp);
|
||||
void lcdcReleaseBus(LCDCDriver *lcdcp);
|
||||
#endif /* LCDC_USE_MUTUAL_EXCLUSION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_LCDC */
|
||||
|
||||
#endif /* SAMA_LCDC_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_matrix.c
|
||||
* @brief SAMA MATRIX support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_MATRIX
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constant */
|
||||
/*===========================================================================*/
|
||||
#define SCFG_OFFSET 0x40u
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
#define MATRIX_SCFG(value) (MATRIX_SCFG0 + (value * 4u))
|
||||
#define MATRIX_SCFG_FIXED_DEFMSTR(value) MATRIX_SCFG0_FIXED_DEFMSTR(value)
|
||||
#define MATRIX_SCFG_DEFMSTR_TYPE(value) MATRIX_SCFG0_DEFMSTR_TYPE(value)
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on MATRIX registers block.
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define mtxEnableWP(mtxp) { \
|
||||
mtxp->MATRIX_WPMR = MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on MATRIX registers block.
|
||||
*
|
||||
* @param[in] matxp pointer to a MATRIX register block.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define mtxDisableWP(mtxp) { \
|
||||
mtxp->MATRIX_WPMR = MATRIX_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Configures peripheral security
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
* @param[in] id PERIPHERAL_ID.
|
||||
* @param[in] mode SECURE_PER or NOT_SECURE_PER.
|
||||
*
|
||||
* @retval true Peripheral is not secured.
|
||||
* @retval false Peripheral is secured.
|
||||
*
|
||||
*/
|
||||
bool mtxConfigPeriphSecurity(Matrix *mtxp, uint32_t id, bool mode) {
|
||||
|
||||
uint32_t mask;
|
||||
mask = id & 0x1F;
|
||||
|
||||
mtxDisableWP(mtxp);
|
||||
if (mode) {
|
||||
mtxp->MATRIX_SPSELR[id / 32] |= (MATRIX_SPSELR_NSECP0 << mask);
|
||||
}
|
||||
else {
|
||||
mtxp->MATRIX_SPSELR[id / 32] &= ~(MATRIX_SPSELR_NSECP0 << mask);
|
||||
}
|
||||
mtxEnableWP(mtxp);
|
||||
|
||||
return (MATRIX0->MATRIX_SPSELR[id / 32] & (MATRIX_SPSELR_NSECP0 << mask)) &
|
||||
(MATRIX1->MATRIX_SPSELR[id / 32] & (MATRIX_SPSELR_NSECP0 << mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associates slave with a kind of master
|
||||
* @note masterID is set only if type is fixed default master.
|
||||
* Specifying the number of a master which is not connected
|
||||
* to the selected slave is equivalent to clearing DEFMSTR_TYPE.
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
* @param[in] slaveID Slave MATRIX ID.
|
||||
* @param[in] type Select from
|
||||
* No default master,
|
||||
* Last access master,
|
||||
* Fixed default master.
|
||||
* @param[in] masterID Master MATRIX ID.
|
||||
*/
|
||||
void mtxConfigDefaultMaster(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t type, uint8_t masterID) {
|
||||
|
||||
mtxDisableWP(mtxp);
|
||||
|
||||
volatile uint32_t *scfgAddress = (uint32_t *) ((uint32_t) mtxp + SCFG_OFFSET + (4u * slaveID));
|
||||
*scfgAddress = MATRIX_SCFG_DEFMSTR_TYPE(type);
|
||||
|
||||
if (type == FIXED_DEFAULT_MASTER) {
|
||||
*scfgAddress = MATRIX_SCFG_FIXED_DEFMSTR(masterID);
|
||||
}
|
||||
mtxEnableWP(mtxp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures slave security region
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
* @param[in] slaveID Slave MATRIX ID.
|
||||
* @param[in] selMask Securable area.
|
||||
* @param[in] readMask Secure for read.
|
||||
* @param[in] writeMask Secure for write.
|
||||
*/
|
||||
void mtxConfigSlaveSec(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t selMask, uint8_t readMask,
|
||||
uint8_t writeMask) {
|
||||
|
||||
mtxDisableWP(mtxp);
|
||||
mtxp->MATRIX_SSR[slaveID] = selMask | (readMask << 8) |
|
||||
(writeMask << 16);
|
||||
mtxEnableWP(mtxp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures split area of region
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
* @param[in] slaveID Slave MATRIX ID.
|
||||
* @param[in] areaSize Split size area.
|
||||
* @param[in] mask Region securable area.
|
||||
*/
|
||||
void mtxSetSlaveSplitAddr(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t areaSize, uint8_t mask) {
|
||||
|
||||
mtxDisableWP(mtxp);
|
||||
uint8_t i = mask, j = 0;
|
||||
uint32_t value = 0;
|
||||
uint32_t pmask = 0;
|
||||
for (i = 1; (i <= mask) && (j < 32); i <<= 1, j += 4) {
|
||||
if (i & mask) {
|
||||
value |= areaSize << j;
|
||||
pmask |= 0x0F << j;
|
||||
}
|
||||
}
|
||||
mtxp->MATRIX_SASSR[slaveID] = (mtxp->MATRIX_SASSR[slaveID] & ~pmask) | value;
|
||||
mtxEnableWP(mtxp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures size area of region
|
||||
* @note Not applicable to internal security type
|
||||
*
|
||||
* @param[in] mtxp pointer to a MATRIX register block.
|
||||
* @param[in] slaveID Slave MATRIX ID.
|
||||
* @param[in] areaSize Size of total area.
|
||||
* @param[in] mask Region securable area.
|
||||
*/
|
||||
void mtxSetSlaveRegionSize(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t areaSize, uint8_t mask) {
|
||||
|
||||
osalDbgCheck(slaveID != 0);
|
||||
|
||||
mtxDisableWP(mtxp);
|
||||
uint8_t i = mask, j = 0;
|
||||
uint32_t value = 0;
|
||||
uint32_t pmask = 0;
|
||||
for (i = 1; (i <= mask) && (j < 32 ); i <<= 1, j += 4) {
|
||||
if (i & mask) {
|
||||
value |= areaSize << j;
|
||||
pmask |= 0x0F << j;
|
||||
}
|
||||
}
|
||||
mtxp->MATRIX_SRTSR[slaveID] = (mtxp->MATRIX_SRTSR[slaveID] & ~pmask) | value;
|
||||
mtxEnableWP(mtxp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the mapping of the chip so that the remap area
|
||||
* mirrors the internal ROM or the EBI CS0.
|
||||
*/
|
||||
void mtxRemapRom(void) {
|
||||
|
||||
AXIMX->AXIMX_REMAP = 0;
|
||||
|
||||
/* Invalidate I-Cache*/
|
||||
L1C_InvalidateICacheAll();
|
||||
|
||||
/* Invalidate Region */
|
||||
cacheInvalidateRegion((void*)0, IRAM_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the mapping of the chip so that the remap area
|
||||
* mirrors the internal ROM or the EBI CS0.
|
||||
*/
|
||||
void mtxRemapRam(void) {
|
||||
|
||||
AXIMX->AXIMX_REMAP = AXIMX_REMAP_REMAP0;
|
||||
|
||||
/* Invalidate I-Cache*/
|
||||
L1C_InvalidateICacheAll();
|
||||
|
||||
/* Clean I-Region */
|
||||
cacheCleanRegion((void*)IRAM_ADDR, IRAM_SIZE);
|
||||
/* Invalidate Region */
|
||||
cacheInvalidateRegion((void*)0, IRAM_SIZE);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,341 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_matrix.h
|
||||
* @brief SAMA MATRIX support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_MATRIX
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_MATRIX_H
|
||||
#define SAMA_MATRIX_H
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name SECURE MATRIX mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief The low area of region is the securable one.
|
||||
*/
|
||||
#define LOWER_AREA_SECURABLE 0x0u
|
||||
|
||||
/**
|
||||
* @brief The upper area of region is the non-securable one.
|
||||
*/
|
||||
#define UPPER_AREA_SECURABLE 0x1u
|
||||
|
||||
/**
|
||||
* @brief Securable area is secured for reads.
|
||||
*/
|
||||
#define SECURE_READ 0x0u
|
||||
|
||||
/**
|
||||
* @brief Securable area is secured for writes.
|
||||
*/
|
||||
#define SECURE_WRITE 0x0u
|
||||
|
||||
/**
|
||||
* @brief Securable area is non-secured for reads.
|
||||
*/
|
||||
#define NOT_SECURE_READ 0x1u
|
||||
|
||||
/**
|
||||
* @brief Securable area is non-secured for writes.
|
||||
*/
|
||||
#define NOT_SECURE_WRITE 0x1u
|
||||
|
||||
/**
|
||||
* @brief Peripheral Securable as secure.
|
||||
*/
|
||||
#define SECURE_PER FALSE
|
||||
|
||||
/**
|
||||
* @brief Peripheral Securable as not-secure.
|
||||
*/
|
||||
#define NOT_SECURE_PER TRUE
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MASTER TYPE MATRIX macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief No Default Master.
|
||||
*/
|
||||
#define NO_DEFAULT_MASTER 0x0u
|
||||
|
||||
/**
|
||||
* @brief Last Default Master.
|
||||
*/
|
||||
#define LAST_DEFAULT_MASTER 0x1u
|
||||
|
||||
/**
|
||||
* @brief Fixed Default Master.
|
||||
*/
|
||||
#define FIXED_DEFAULT_MASTER 0x2u
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name REGION MATRIX MASK macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Region 0.
|
||||
*/
|
||||
#define REGION_0_MSK (0x1u << 0)
|
||||
|
||||
/**
|
||||
* @brief Region 1.
|
||||
*/
|
||||
#define REGION_1_MSK (0x1u << 1)
|
||||
|
||||
/**
|
||||
* @brief Region 2.
|
||||
*/
|
||||
#define REGION_2_MSK (0x1u << 2)
|
||||
|
||||
/**
|
||||
* @brief Region 3.
|
||||
*/
|
||||
#define REGION_3_MSK (0x1u << 3)
|
||||
|
||||
/**
|
||||
* @brief Region 4.
|
||||
*/
|
||||
#define REGION_4_MSK (0x1u << 4)
|
||||
|
||||
/**
|
||||
* @brief Region 5.
|
||||
*/
|
||||
#define REGION_5_MSK (0x1u << 5)
|
||||
|
||||
/**
|
||||
* @brief Region 6.
|
||||
*/
|
||||
#define REGION_6_MSK (0x1u << 6)
|
||||
|
||||
/**
|
||||
* @brief Region 7.
|
||||
*/
|
||||
#define REGION_7_MSK (0x1u << 7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name REGION MATRIX macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Region 0.
|
||||
*/
|
||||
#define REGION_0 0x0u
|
||||
|
||||
/**
|
||||
* @brief Region 1.
|
||||
*/
|
||||
#define REGION_1 0x1u
|
||||
|
||||
/**
|
||||
* @brief Region 2.
|
||||
*/
|
||||
#define REGION_2 0x2u
|
||||
|
||||
/**
|
||||
* @brief Region 3.
|
||||
*/
|
||||
#define REGION_3 0x3u
|
||||
|
||||
/**
|
||||
* @brief Region 4.
|
||||
*/
|
||||
#define REGION_4 0x4u
|
||||
|
||||
/**
|
||||
* @brief Region 5.
|
||||
*/
|
||||
#define REGION_5 0x5u
|
||||
|
||||
/**
|
||||
* @brief Region 6.
|
||||
*/
|
||||
#define REGION_6 0x6u
|
||||
|
||||
/**
|
||||
* @brief Region 7.
|
||||
*/
|
||||
#define REGION_7 0x7u
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name AREA SIZE MATRIX macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Area size 4 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_4K 0x0u
|
||||
|
||||
/**
|
||||
* @brief Area size 8 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_8K 0x1u
|
||||
|
||||
/**
|
||||
* @brief Area size 16 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_16K 0x2u
|
||||
|
||||
/**
|
||||
* @brief Area size 32 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_32K 0x3u
|
||||
|
||||
/**
|
||||
* @brief Area size 64 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_64K 0x4u
|
||||
|
||||
/**
|
||||
* @brief Area size 128 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_128K 0x5u
|
||||
|
||||
/**
|
||||
* @brief Area size 256 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_256K 0x6u
|
||||
|
||||
/**
|
||||
* @brief Area size 512 KB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_512K 0x7u
|
||||
|
||||
/**
|
||||
* @brief Area size 1 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_1M 0x8u
|
||||
|
||||
/**
|
||||
* @brief Area size 2 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_2M 0x9u
|
||||
|
||||
/**
|
||||
* @brief Area size 4 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_4M 0xAu
|
||||
|
||||
/**
|
||||
* @brief Area size 8 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_8M 0xBu
|
||||
|
||||
/**
|
||||
* @brief Area size 16 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_16M 0xCu
|
||||
|
||||
/**
|
||||
* @brief Area size 32 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_32M 0xDu
|
||||
|
||||
/**
|
||||
* @brief Area size 64 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_64M 0xEu
|
||||
|
||||
/**
|
||||
* @brief Area size 128 MB.
|
||||
*/
|
||||
#define MATRIX_AREA_SIZE_128M 0xFu
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Configure LANSECH per Region.
|
||||
*
|
||||
* @param[in] region Region to configure.
|
||||
* @param[in] lansech Securable mode.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define mtxRegionLansech(region, lansech) (lansech << region)
|
||||
|
||||
/**
|
||||
* @brief Configure RDNSECH per Region.
|
||||
*
|
||||
* @param[in] region Region to configure.
|
||||
* @param[in] rdnsech Read securable mode.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define mtxRegionRdnsech(region, rdnsech) (rdnsech << region)
|
||||
|
||||
/**
|
||||
* @brief Configure WRNSECH per Region.
|
||||
*
|
||||
* @param[in] region Region to configure.
|
||||
* @param[in] wrnsech Write securable mode.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define mtxRegionWrnsech(region, wrnsech) (wrnsech << region)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
bool mtxConfigPeriphSecurity(Matrix *mtxp, uint32_t id, bool mode);
|
||||
void mtxConfigDefaultMaster(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t type, uint8_t masterID);
|
||||
void mtxConfigSlaveSec(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t selMask, uint8_t readMask,
|
||||
uint8_t writeMask);
|
||||
void mtxSetSlaveSplitAddr(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t area, uint8_t mask);
|
||||
void mtxSetSlaveRegionSize(Matrix *mtxp, uint8_t slaveID,
|
||||
uint8_t areaSize, uint8_t mask);
|
||||
void mtxRemapRom(void);
|
||||
void mtxRemapRam(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_MATRIX_H */
|
||||
|
||||
/** @} */
|
|
@ -1,548 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_onewire.c
|
||||
* @brief SAMA ONEWIRE support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_ONEWIRE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (SAMA_USE_ONEWIRE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Delays in standard speed mode.
|
||||
* @{
|
||||
*/
|
||||
#define A US2RTC(SAMA_PCK, 6)
|
||||
#define B US2RTC(SAMA_PCK, 64)
|
||||
#define C US2RTC(SAMA_PCK, 60)
|
||||
#define D US2RTC(SAMA_PCK, 10)
|
||||
#define E US2RTC(SAMA_PCK, 9)
|
||||
#define F US2RTC(SAMA_PCK, 55)
|
||||
#define G US2RTC(SAMA_PCK, 0)
|
||||
#define H US2RTC(SAMA_PCK, 480)
|
||||
#define I US2RTC(SAMA_PCK, 70)
|
||||
#define J US2RTC(SAMA_PCK, 410)
|
||||
/** @} */
|
||||
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PAD_INPUT_MODE PAL_SAMA_FUNC_GPIO | \
|
||||
PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_OPD_OPENDRAIN | \
|
||||
PAL_SAMA_PUEN_PULLUP | \
|
||||
PAL_MODE_SECURE
|
||||
|
||||
#define PAD_OUTPUT_MODE PAL_SAMA_FUNC_GPIO | \
|
||||
PAL_SAMA_DIR_OUTPUT | \
|
||||
PAL_SAMA_OPD_OPENDRAIN | \
|
||||
PAL_SAMA_PUEN_PULLUP | \
|
||||
PAL_MODE_SECURE
|
||||
#else
|
||||
#define PAD_INPUT_MODE PAL_SAMA_FUNC_GPIO | \
|
||||
PAL_SAMA_DIR_INPUT | \
|
||||
PAL_SAMA_OPD_OPENDRAIN | \
|
||||
PAL_SAMA_PUEN_PULLUP
|
||||
|
||||
#define PAD_OUTPUT_MODE PAL_SAMA_FUNC_GPIO | \
|
||||
PAL_SAMA_DIR_OUTPUT | \
|
||||
PAL_SAMA_OPD_OPENDRAIN | \
|
||||
PAL_SAMA_PUEN_PULLUP
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Set ONEWIRE pin in output mode.
|
||||
*
|
||||
* @param[in] onewp pointer to a ONEWIRE driver.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define onewireSetPinOutput(onewp) { \
|
||||
palSetLineMode(onewp->config->line, PAD_OUTPUT_MODE); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ONEWIRE pin in input mode.
|
||||
*
|
||||
* @param[in] onewp pointer to a ONEWIRE driver.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define onewireSetPinInput(onewp) { \
|
||||
palSetLineMode(onewp->config->line, PAD_INPUT_MODE); \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
ONEWIREDriver ONEWD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Low level ONEWIRE driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void onewire_lld_init(void) {
|
||||
|
||||
onewireObjectInit(&ONEWD0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void onewire_lld_start(ONEWIREDriver *onewp) {
|
||||
|
||||
/* Set the ONEWIRE pin in output mode. */
|
||||
onewireSetPinOutput(onewp);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the ONEWIRE driver.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void onewire_lld_stop(ONEWIREDriver *onewp) {
|
||||
(void) onewp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a Reset on ONEWIRE pin.
|
||||
* The reset detect the slave presence on the pin
|
||||
* and ready it for a command.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @return result result of the reset, if 0 a slave is detected
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
bool onewire_lld_reset(ONEWIREDriver *onewp) {
|
||||
|
||||
bool result = TRUE;
|
||||
|
||||
/* At the beginning set the pin in output mode. */
|
||||
onewireSetPinOutput(onewp);
|
||||
|
||||
/* Wait 0 microseconds. */
|
||||
chSysPolledDelayX(G);
|
||||
/* Drives pin low. */
|
||||
palClearLine(onewp->config->line);
|
||||
/* Wait 480 microseconds. */
|
||||
chSysPolledDelayX(H);
|
||||
/* Drives pin high. */
|
||||
palSetLine(onewp->config->line);
|
||||
/* Wait 70 microseconds. */
|
||||
chSysPolledDelayX(I);
|
||||
/* Set the pin in input mode. */
|
||||
onewireSetPinInput(onewp);
|
||||
/* Read the pin logic state. */
|
||||
result = palReadLine(onewp->config->line);
|
||||
/* Wait 410 microseconds. */
|
||||
chSysPolledDelayX(J);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a bit through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] value bit value to write
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void onewire_lld_write_bit(ONEWIREDriver *onewp, uint8_t value) {
|
||||
|
||||
osalDbgAssert((value == 0u) || (value == 1u),
|
||||
"invalid value");
|
||||
|
||||
/* Set the pin in output mode. */
|
||||
onewireSetPinOutput(onewp);
|
||||
|
||||
if (value) {
|
||||
/* Write '1' bit */
|
||||
/* Drives pin low. */
|
||||
palClearLine(onewp->config->line);
|
||||
/* Wait 6 microsecond. */
|
||||
chSysPolledDelayX(A);
|
||||
/* Drives pin high. */
|
||||
palSetLine(onewp->config->line);
|
||||
/* Wait 64 microseconds to complete the time slot and recovery. */
|
||||
chSysPolledDelayX(B);
|
||||
}
|
||||
else {
|
||||
/* Write '0' bit */
|
||||
/* Drives pin low. */
|
||||
palClearLine(onewp->config->line);
|
||||
/* Wait 60 microsecond. */
|
||||
chSysPolledDelayX(C);
|
||||
/* Drives pin high. */
|
||||
palSetLine(onewp->config->line);
|
||||
/* Wait 10 microseconds for recovery. */
|
||||
chSysPolledDelayX(D);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a bit through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @return value bit read
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint8_t onewire_lld_read_bit(ONEWIREDriver *onewp) {
|
||||
|
||||
uint8_t value;
|
||||
|
||||
/* At the beginning set the pin in output mode. */
|
||||
onewireSetPinOutput(onewp);
|
||||
|
||||
/* Drives pin low. */
|
||||
palClearLine(onewp->config->line);
|
||||
/* Wait 6 microsecond. */
|
||||
chSysPolledDelayX(A);
|
||||
/* Drives pin high. */
|
||||
palSetLine(onewp->config->line);
|
||||
/* Wait 9 microseconds. */
|
||||
chSysPolledDelayX(E);
|
||||
/* Set the pin in input mode. */
|
||||
onewireSetPinInput(onewp);
|
||||
/* Read the pin logic state. */
|
||||
value = palReadLine(onewp->config->line);
|
||||
/* Wait 55 microseconds. */
|
||||
chSysPolledDelayX(F);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a byte through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] byte byte to write
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void onewire_lld_write_byte(ONEWIREDriver *onewp, uint8_t byte) {
|
||||
|
||||
uint8_t i;
|
||||
|
||||
/* Loop to write each bit in the byte, LS-bit first */
|
||||
for (i = 0; i < 8; i++) {
|
||||
onewire_lld_write_bit(onewp, (byte & 0x01));
|
||||
/* Shift the data byte for the next bit */
|
||||
byte >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a byte through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* return value byte read
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint8_t onewire_lld_read_byte(ONEWIREDriver *onewp) {
|
||||
|
||||
uint8_t i;
|
||||
uint8_t value = 0;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* Shift the result to get it ready for the next bit */
|
||||
value >>= 1;
|
||||
/* If result is one, then set MS bit */
|
||||
if (onewire_lld_read_bit(onewp))
|
||||
value |= 0x80;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief ONEWIRE driver initialization.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireInit(void) {
|
||||
|
||||
onewire_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the standard part of a @p ONEWIREDriver structure.
|
||||
*
|
||||
* @param[out] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void onewireObjectInit(ONEWIREDriver *onewp) {
|
||||
|
||||
onewp->state = ONEW_STOP;
|
||||
onewp->config = NULL;
|
||||
|
||||
osalMutexObjectInit(&onewp->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] config pointer to the @p ONEWIREConfig object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireStart(ONEWIREDriver *onewp, const ONEWIREConfig *config) {
|
||||
|
||||
osalDbgCheck((onewp != NULL) && (config != NULL));
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((onewp->state == ONEW_STOP) || (onewp->state == ONEW_READY),
|
||||
"invalid state");
|
||||
onewp->config = config;
|
||||
onewire_lld_start(onewp);
|
||||
onewp->state = ONEW_READY;
|
||||
osalSysUnlock();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the ONEWIRE driver.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireStop(ONEWIREDriver *onewp) {
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert((onewp->state == ONEW_STOP) || (onewp->state == ONEW_READY),
|
||||
"invalid state");
|
||||
|
||||
onewire_lld_stop(onewp);
|
||||
onewp->config = NULL;
|
||||
onewp->state = ONEW_STOP;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a block of bytes through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
* @param[in] n number of bytes to write
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireWriteBlockI(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n) {
|
||||
|
||||
uint32_t i;
|
||||
(onewp)->state = ONEW_ACTIVE;
|
||||
for (i = 0; i < n; i++) {
|
||||
onewire_lld_write_byte(onewp, txbuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a block of bytes through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] txbuf the pointer to the transmit buffer
|
||||
* @param[in] n number of bytes to write
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireWriteBlock(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n) {
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert(onewp->state == ONEW_READY, "not ready");
|
||||
onewireWriteBlockI(onewp, txbuf, n);
|
||||
|
||||
(onewp)->state = ONEW_READY;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a block of bytes through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[out]rxbuf pointer to the receive buffer
|
||||
* @param[in] n number of bytes to read
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireReadBlockI(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n) {
|
||||
|
||||
uint32_t i;
|
||||
(onewp)->state = ONEW_ACTIVE;
|
||||
for (i = 0; i < n; i++) {
|
||||
rxbuf[i] = onewire_lld_read_byte(onewp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a block of bytes through ONEWIRE pin.
|
||||
*
|
||||
* @param[in] onewirep pointer to the @p ONEWIREDriver object
|
||||
* @param[out]rxbuf pointer to the receive buffer
|
||||
* @param[in] n number of bytes to read
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireReadBlock(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n) {
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
// osalSysLock();
|
||||
osalDbgAssert(onewp->state == ONEW_READY, "not ready");
|
||||
onewireReadBlockI(onewp, rxbuf, n);
|
||||
(onewp)->state = ONEW_READY;
|
||||
// osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a Reset on ONEWIRE pin.
|
||||
* The reset detect the slave presence on the pin
|
||||
* and ready it for a command.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @return result result of the reset, if 0 a slave is detected
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool onewireReset(ONEWIREDriver *onewp) {
|
||||
|
||||
bool detect = TRUE;
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert(onewp->state == ONEW_READY,
|
||||
"invalid state");
|
||||
detect = onewire_lld_reset(onewp);
|
||||
osalSysUnlock();
|
||||
|
||||
return detect;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Sends a command.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] cmdp pointer command byte
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireCommandI(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n) {
|
||||
|
||||
uint32_t i;
|
||||
(onewp)->state = ONEW_ACTIVE;
|
||||
for (i = 0; i < n; i++) {
|
||||
onewire_lld_write_byte(onewp, cmdp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Sends a command.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
* @param[in] cmdp pointer to command
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireCommand(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n) {
|
||||
|
||||
osalDbgCheck((onewp != NULL) && (cmdp != NULL));
|
||||
|
||||
// osalSysLock();
|
||||
|
||||
osalDbgAssert(onewp->state == ONEW_READY, "not ready");
|
||||
|
||||
onewireCommandI(onewp, cmdp, n);
|
||||
(onewp)->state = ONEW_READY;
|
||||
// osalSysUnlock();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gains exclusive access to the ONEWIRE bus.
|
||||
* @details This function tries to gain ownership to the ONEWIRE bus, if the bus
|
||||
* is already being used then the invoking thread is queued.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireAcquireBus(ONEWIREDriver *onewp) {
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
osalMutexLock(&onewp->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases exclusive access to the ONEWIRE bus.
|
||||
*
|
||||
* @param[in] onewp pointer to the @p ONEWIREDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void onewireReleaseBus(ONEWIREDriver *onewp) {
|
||||
|
||||
osalDbgCheck(onewp != NULL);
|
||||
|
||||
osalMutexUnlock(&onewp->mutex);
|
||||
}
|
||||
|
||||
#endif /* SAMA_USE_ONEWIRE == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_onewire.h
|
||||
* @brief SAMA ONEWIRE support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_ONEWIRE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_ONEWIRE_LLD_H
|
||||
#define SAMA_ONEWIRE_LLD_H
|
||||
|
||||
/**
|
||||
* @brief Using the ONEWIRE driver.
|
||||
*/
|
||||
#if !defined(SAMA_USE_ONEWIRE) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_ONEWIRE FALSE
|
||||
#endif
|
||||
|
||||
#if (SAMA_USE_ONEWIRE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
ONEW_UNINIT = 0, /**< Not initialized. */
|
||||
ONEW_STOP = 1, /**< Stopped. */
|
||||
ONEW_READY = 2, /**< Active. */
|
||||
ONEW_ACTIVE = 3 /**< Active. */
|
||||
} onewstate_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing a ONEWIRE driver.
|
||||
*/
|
||||
typedef struct ONEWIREDriver ONEWIREDriver;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Line for the data IO
|
||||
*/
|
||||
uint32_t line;
|
||||
} ONEWIREConfig;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure representing an ONEWIRE driver.
|
||||
*/
|
||||
struct ONEWIREDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
onewstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const ONEWIREConfig *config;
|
||||
/**
|
||||
* @brief Mutex protecting the bus.
|
||||
*/
|
||||
mutex_t mutex;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern ONEWIREDriver ONEWD0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void onewireInit(void);
|
||||
void onewireObjectInit(ONEWIREDriver *onewp);
|
||||
void onewireStart(ONEWIREDriver *onewp, const ONEWIREConfig *config);
|
||||
void onewireStop(ONEWIREDriver *onewp);
|
||||
bool onewireReset(ONEWIREDriver *onewp);
|
||||
void onewireCommand(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n);
|
||||
void onewireWriteBlock(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n);
|
||||
void onewireReadBlock(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n);
|
||||
void onewireAcquireBus(ONEWIREDriver *onewp);
|
||||
void onewireReleaseBus(ONEWIREDriver *onewp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_ONEWIRE */
|
||||
|
||||
#endif /* SAMA_ONEWIRE_LLD_H */
|
||||
|
||||
/** @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_registry.h
|
||||
* @brief SAMA5D2x capabilities registry.
|
||||
*
|
||||
* @addtogroup HAL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_REGISTRY_H
|
||||
#define SAMA_REGISTRY_H
|
||||
|
||||
/**
|
||||
* @brief Sub-family identifier.
|
||||
*/
|
||||
#if !defined(SAMA5D2X) || defined(__DOXYGEN__)
|
||||
#define SAMA5D2X
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Common features. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Platform capabilities. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name SAMA5D27 capabilities
|
||||
* @{
|
||||
*/
|
||||
/*===========================================================================*/
|
||||
/* SAMA5D27. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if defined(SAMA5D27) || defined(__DOXYGEN__)
|
||||
|
||||
#endif /* defined(SAMA5D27) */
|
||||
|
||||
/* PIO attributes.*/
|
||||
#define SAMA_HAS_PIOA TRUE
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PIOA_BASE 0xFC039000U
|
||||
#else
|
||||
#define PIOA_BASE 0xFC038000U
|
||||
#endif
|
||||
|
||||
#define SAMA_HAS_PIOB TRUE
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PIOB_BASE 0xFC039040U
|
||||
#else
|
||||
#define PIOB_BASE 0xFC038040U
|
||||
#endif
|
||||
|
||||
#define SAMA_HAS_PIOC TRUE
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PIOC_BASE 0xFC039080U
|
||||
#else
|
||||
#define PIOC_BASE 0xFC038080U
|
||||
#endif
|
||||
|
||||
#define SAMA_HAS_PIOD TRUE
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
#define PIOD_BASE 0xFC0390C0U
|
||||
#else
|
||||
#define PIOD_BASE 0xFC0380C0U
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#endif /* SAMA_REGISTRY_H */
|
||||
|
||||
/** @} */
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_rstc.h
|
||||
* @brief SAMA RSTC helper driver header.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_RSTC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _SAMA_RSTC_
|
||||
#define _SAMA_RSTC_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name RESET SOURCE MACROS
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief No access allowed.
|
||||
*/
|
||||
#define RSTC_GENERAL 0x0U
|
||||
|
||||
/**
|
||||
* @brief Only write access allowed.
|
||||
*/
|
||||
#define RSTC_WKUP 0x1U
|
||||
|
||||
/**
|
||||
* @brief Only read access allowed.
|
||||
*/
|
||||
#define RSTC_WDT 0x2U
|
||||
|
||||
/**
|
||||
* @brief Read and Write access allowed.
|
||||
*/
|
||||
#define RSTC_SOFT 0x3U
|
||||
|
||||
/**
|
||||
* @brief Read and Write access allowed.
|
||||
*/
|
||||
#define RSTC_USER 0x4U
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Generic RSTC operations
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Enable/Disable the detection of a low level on the pin NRST
|
||||
* as User Reset.
|
||||
* @param[in] enable
|
||||
*/
|
||||
#define rstcSetUserResetEnable(enable) { \
|
||||
if (enable) { \
|
||||
RSTC->RSTC_MR |= RSTC_MR_URSTEN | RSTC_MR_KEY_PASSWD; \
|
||||
} else { \
|
||||
RSTC->RSTC_MR &= ~RSTC_MR_URSTEN; \
|
||||
RSTC->RSTC_MR |= RSTC_MR_KEY_PASSWD; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the interrupt of a User Reset.
|
||||
* @param[in] enable
|
||||
*/
|
||||
#define rstcSetUserResetInterruptEnable(enable) { \
|
||||
if (enable) { \
|
||||
RSTC->RSTC_MR |= RSTC_MR_URSTIEN | RSTC_MR_KEY_PASSWD; \
|
||||
} else { \
|
||||
RSTC->RSTC_MR &= ~RSTC_MR_URSTIEN; \
|
||||
RSTC->RSTC_MR |= RSTC_MR_KEY_PASSWD; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform a processor and peripheral reset.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define rstcResetProcessorAndPeripheral() { \
|
||||
RSTC->RSTC_CR = RSTC_CR_PERRST | RSTC_CR_PROCRST | RSTC_MR_KEY_PASSWD; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform a processor reset.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define rstcResetProcessor() { \
|
||||
RSTC->RSTC_CR = RSTC_CR_PROCRST | RSTC_CR_KEY_PASSWD; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform a peripheral reset.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define rstcResetPeripheral() { \
|
||||
RSTC->RSTC_CR = RSTC_CR_PERRST | RSTC_MR_KEY_PASSWD; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report the cause of the last processor reset.
|
||||
*
|
||||
* @param[out] status Cause of the reset
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define rstcGetStatus(status) { \
|
||||
uint32_t sr = RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk; \
|
||||
switch (sr) { \
|
||||
case RSTC_SR_RSTTYP_GENERAL_RST: \
|
||||
status = RSTC_GENERAL; \
|
||||
break; \
|
||||
case RSTC_SR_RSTTYP_WKUP_RST: \
|
||||
status = RSTC_WKUP; \
|
||||
break; \
|
||||
case RSTC_SR_RSTTYP_WDT_RST: \
|
||||
status = RSTC_WDT; \
|
||||
break; \
|
||||
case RSTC_SR_RSTTYP_SOFT_RST: \
|
||||
status = RSTC_SOFT; \
|
||||
break; \
|
||||
case RSTC_SR_RSTTYP_USER_RST: \
|
||||
status = RSTC_USER; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_RSTC_H */
|
||||
|
||||
/** @} */
|
|
@ -1,599 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_secumod.c
|
||||
* @brief SAMA SECUMOD support code.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_SECUMOD
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if SAMA_USE_SECUMOD || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief SEC driver identifier.
|
||||
*/
|
||||
SECDriver SECD0;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constant */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief SECURAM interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_SECURAM_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t ramaccsr, sr, sysr;
|
||||
uint32_t rwx;
|
||||
uint32_t i;
|
||||
|
||||
ramaccsr = SECUMOD->SECUMOD_RAMACCSR;
|
||||
sr = SECUMOD->SECUMOD_SR;
|
||||
|
||||
for (i = 0; i < SECUMOD_RAM_REGIONS; i++) {
|
||||
rwx = (ramaccsr >> (2 * i)) & 3;
|
||||
if (rwx != RAMACCSR_NO_VIOLATION && SECD0.config->securam_callback != NULL)
|
||||
SECD0.config->securam_callback(&SECD0);
|
||||
}
|
||||
|
||||
/* process the end of erase signalling */
|
||||
do {
|
||||
sysr = SECUMOD->SECUMOD_SYSR;
|
||||
} while (sysr & SECUMOD_SYSR_ERASE_ON);
|
||||
|
||||
if (SECUMOD_SYSR_ERASE_DONE == (sysr & SECUMOD_SYSR_ERASE_DONE)) {
|
||||
/* Clear the flag ERASE_DONE */
|
||||
SECUMOD->SECUMOD_SYSR = SECUMOD_SYSR_ERASE_DONE;
|
||||
if (SECD0.config->erased_callback != NULL)
|
||||
SECD0.config->erased_callback(&SECD0);
|
||||
}
|
||||
|
||||
/* wait at least one slow clock */
|
||||
chSysPolledDelayX(SAMA_PCK / SAMA_SLOW_CLK);
|
||||
|
||||
/* Clear RAM access violation flags */
|
||||
SECUMOD->SECUMOD_RAMACCSR = ramaccsr;
|
||||
/* Clear corresponding alarm flag bit */
|
||||
SECUMOD->SECUMOD_SCR = sr;
|
||||
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SECUMOD interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_SECUMOD_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
uint32_t sr, nimpr;
|
||||
|
||||
/* Read alarm status */
|
||||
sr = SECUMOD->SECUMOD_SR;
|
||||
nimpr = SECUMOD->SECUMOD_NIMPR;
|
||||
|
||||
if ((sr & SECUMOD_SR_SHLDM) && (nimpr & SECUMOD_NIMPR_SHLDM)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_SHLDM);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DBLFM) && (nimpr & SECUMOD_NIMPR_DBLFM)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_DBLFM);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_TST) && (nimpr & SECUMOD_NIMPR_TST)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_TST);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_JTAG) && (nimpr & SECUMOD_NIMPR_JTAG)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_JTAG);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_MCKM) && (nimpr & SECUMOD_NIMPR_MCKM)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_MCKM);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_TPML) && (nimpr & SECUMOD_NIMPR_TPML)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_TPML);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_TPMH) && (nimpr & SECUMOD_NIMPR_TPMH)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_TPMH);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_VDDBUL) && (nimpr & SECUMOD_NIMPR_VDDBUL)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_VDDBUL);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_VDDBUH) && (nimpr & SECUMOD_NIMPR_VDDBUH)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_VDDBUH);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_VDDCOREL) && (nimpr & SECUMOD_NIMPR_VDDCOREL)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_VDDCOREL);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_VDDCOREH) && (nimpr & SECUMOD_NIMPR_VDDCOREH)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_VDDCOREH);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET0) && (nimpr & SECUMOD_NIMPR_DET0)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU0);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET1) && (nimpr & SECUMOD_NIMPR_DET1)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU1);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET2) && (nimpr & SECUMOD_NIMPR_DET2)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU2);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET3) && (nimpr & SECUMOD_NIMPR_DET3)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU3);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET4) && (nimpr & SECUMOD_NIMPR_DET4)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU4);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET5) && (nimpr & SECUMOD_NIMPR_DET5)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU5);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET6) && (nimpr & SECUMOD_NIMPR_DET6)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU6);
|
||||
}
|
||||
else if ((sr & SECUMOD_SR_DET7) && (nimpr & SECUMOD_NIMPR_DET7)) {
|
||||
SECD0.secumod_callback(&SECD0, SEC_EVENT_PIOBU7);
|
||||
}
|
||||
else {
|
||||
(void) 0;
|
||||
}
|
||||
|
||||
/* wait at least one slow clock */
|
||||
chSysPolledDelayX(SAMA_PCK / SAMA_SLOW_CLK);
|
||||
|
||||
/* Clear corresponding alarm flag bit */
|
||||
SECUMOD->SECUMOD_SCR = sr;
|
||||
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Configures PIOBU pads according to configuration struct.
|
||||
*
|
||||
* @param[in] listp pointer to a PIOBUConfig array
|
||||
* @param[in] length length of array
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void piobu_config(PIOBUConfig *listp, size_t length) {
|
||||
uint8_t i;
|
||||
uint32_t cfg;
|
||||
uint32_t index;
|
||||
PIOBUConfig *piobup;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
index = listp[i].pinIndex;
|
||||
piobup = &listp[i];
|
||||
|
||||
/* AFV and RFV fields must be set to 0 when dynamic intrusion is selected. */
|
||||
if (piobup->dynamic) {
|
||||
cfg = 0;
|
||||
} else {
|
||||
cfg = (piobup->afv << SECUMOD_PIOBU_AFV_Pos ) | (piobup->rfv << SECUMOD_PIOBU_RFV_Pos);
|
||||
}
|
||||
|
||||
if (piobup->mode) {
|
||||
cfg |= SECUMOD_PIOBU_OUTPUT;
|
||||
if (piobup->outputLevel)
|
||||
cfg |= SECUMOD_PIOBU_PIO_SOD;
|
||||
}
|
||||
|
||||
cfg |= piobup->pullUpState << SECUMOD_PIOBU_PULLUP_Pos;
|
||||
|
||||
if (piobup->scheduled)
|
||||
cfg |= SECUMOD_PIOBU_SCHEDULE;
|
||||
|
||||
if (piobup->inputDefaultLevel)
|
||||
cfg |= SECUMOD_PIOBU_SWITCH;
|
||||
|
||||
/* FILTER3_5 and DYNSTAT fields exist only for even PIOBUs */
|
||||
if (0 == (index & 0x01)) {
|
||||
if (piobup->dynamic)
|
||||
cfg |= SECUMOD_PIOBU_DYNSTAT;
|
||||
|
||||
if (piobup->filter3_5)
|
||||
cfg |= SECUMOD_PIOBU_FILTER3_5;
|
||||
}
|
||||
SECUMOD->SECUMOD_PIOBU[index] = cfg;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low level SEC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sec_lld_init(void) {
|
||||
|
||||
/* Driver initialization.*/
|
||||
secObjectInit(&SECD0);
|
||||
SECD0.sec = SECUMOD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the SEC peripheral.
|
||||
*
|
||||
* @param[in] secp pointer to the @p SECDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sec_lld_start(SECDriver *secp) {
|
||||
|
||||
uint8_t i;
|
||||
|
||||
if (secp->state == SEC_STOP) {
|
||||
/* Clock activation. */
|
||||
pmcEnableSEC();
|
||||
|
||||
/* Register Reset */
|
||||
secp->sec->SECUMOD_NIDPR = SECUMOD_NIDPR_ALL;
|
||||
secumodSetNormalModeProtections(~SECUMOD_NMPR_ALL);
|
||||
|
||||
/*
|
||||
* Configure interrupts
|
||||
*/
|
||||
aicSetIntSourceType(ID_SECUMOD, INT_LEVEL_SENSITIVE);
|
||||
aicSetSourcePriority(ID_SECUMOD, SAMA_SECUMOD_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_SECUMOD, SAMA_SECUMOD_HANDLER);
|
||||
|
||||
aicSetIntSourceType(ID_SECURAM, INT_LEVEL_SENSITIVE);
|
||||
aicSetSourcePriority(ID_SECURAM, SAMA_SECURAM_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_SECURAM, SAMA_SECURAM_HANDLER);
|
||||
|
||||
/* Enabling interrupt. */
|
||||
aicEnableInt(ID_SECUMOD);
|
||||
aicEnableInt(ID_SECURAM);
|
||||
}
|
||||
|
||||
uint32_t ramacc_cfg = 0;
|
||||
|
||||
/* Select mode normal or backup*/
|
||||
secp->sec->SECUMOD_CR = secp->config->cr;
|
||||
|
||||
/* Configure JTAGCR */
|
||||
secp->sec->SECUMOD_JTAGCR = secp->config->jtagcr;
|
||||
|
||||
/* Configure region rights. */
|
||||
for (i = 0; i < SECUMOD_RAM_REGIONS; i++) {
|
||||
ramacc_cfg |= (secp->config->region[i].mode & 0x3u) << (i * 2);
|
||||
}
|
||||
secp->sec->SECUMOD_RAMACC = ramacc_cfg;
|
||||
|
||||
/* Configure PIOBU pads. */
|
||||
piobu_config(secp->config->list, secp->config->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SEC peripheral.
|
||||
*
|
||||
* @param[in] secp pointer to the @p SECDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void sec_lld_stop(SECDriver *secp) {
|
||||
|
||||
secp->sec->SECUMOD_NMPR &= ~(0xFF << 16);
|
||||
secp->sec->SECUMOD_NIDPR |= (0xFF << 16);
|
||||
|
||||
aicDisableInt(ID_SECURAM);
|
||||
aicDisableInt(ID_SECUMOD);
|
||||
|
||||
pmcDisableSEC();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief SEC Driver initialization.
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void secInit(void) {
|
||||
|
||||
sec_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the standard part of a @p SECDriver structure.
|
||||
*
|
||||
* @param[out] secp pointer to a @p SECDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void secObjectInit(SECDriver *secp) {
|
||||
|
||||
secp->state = SEC_STOP;
|
||||
secp->config = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the SEC peripheral.
|
||||
*
|
||||
* @param[in] secp pointer to a @p SECDriver object
|
||||
* @param[in] config pointer to a @p SECConfig object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void secStart(SECDriver *secp, const SECConfig *config) {
|
||||
|
||||
osalDbgCheck((secp != NULL) && (config != NULL));
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((secp->state == SEC_STOP), "invalid state");
|
||||
secp->config = config;
|
||||
sec_lld_start(secp);
|
||||
secp->state = SEC_ACTIVE;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the SEC peripheral.
|
||||
*
|
||||
* @param[in] secp pointer to a @p SECDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void secStop(SECDriver *secp) {
|
||||
|
||||
osalDbgCheck(secp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert((secp->state == SEC_STOP) || (secp->state == SEC_ACTIVE),
|
||||
"invalid state");
|
||||
|
||||
sec_lld_stop(secp);
|
||||
secp->config = NULL;
|
||||
secp->state = SEC_STOP;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables or disables SECUMOD callbacks.
|
||||
* @details This function enables or disables callbacks, use a @p NULL pointer
|
||||
* in order to disable a callback.
|
||||
* @note The function can be called from any context.
|
||||
*
|
||||
* @param[in] secp pointer to SECUMOD driver structure
|
||||
* @param[in] sources Bitwise OR of protections.
|
||||
* @param[in] callback callback function pointer or @p NULL
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void secSetCallback(SECDriver *secp, uint32_t sources, secumod_callback_t callback) {
|
||||
|
||||
osalDbgCheck(secp != NULL);
|
||||
|
||||
syssts_t sts;
|
||||
|
||||
/* Entering a reentrant critical zone.*/
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
|
||||
if (callback != NULL) {
|
||||
|
||||
/* IRQ sources enabled only after setting up the callback.*/
|
||||
secp->secumod_callback = callback;
|
||||
secp->sec->SECUMOD_NIEPR = sources;
|
||||
if (SECUMOD->SECUMOD_NIMPR != sources) {
|
||||
secumodToggleProtectionReg();
|
||||
secp->sec->SECUMOD_NIEPR = sources;
|
||||
}
|
||||
}
|
||||
else {
|
||||
secp->sec->SECUMOD_NIDPR = sources;
|
||||
|
||||
/* Callback set to NULL only after disabling the IRQ sources.*/
|
||||
secp->secumod_callback = NULL;
|
||||
}
|
||||
|
||||
/* Leaving a reentrant critical zone.*/
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set JTAG protection options of SECUMOD.
|
||||
*
|
||||
* @param[in] reset Whether preventing debug state and BSD (Boundary Scan Diagnostics) to work.
|
||||
* @param[in] permissions Debug permissions.
|
||||
* @param[in] ack Whether monitor the DBGACK signal.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void secumodSetJtagProtection(bool reset, uint8_t permissions,
|
||||
bool ack) {
|
||||
|
||||
uint32_t jtagcr;
|
||||
jtagcr = permissions << SECUMOD_JTAGCR_CA5_DEBUG_MODE_Pos;
|
||||
|
||||
if (reset)
|
||||
jtagcr |= SECUMOD_JTAGCR_FNTRST;
|
||||
|
||||
if (ack)
|
||||
jtagcr |= SECUMOD_JTAGCR_CA5_DEBUG_MON;
|
||||
|
||||
SECUMOD->SECUMOD_JTAGCR = jtagcr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tuning dynamic signatures by period and threshold.
|
||||
*
|
||||
* @param[in] period Signature Clock Period.
|
||||
* @param[in] detection_thr Error Detection Threshold.
|
||||
* @param[in] reset_thr Error Counter Reset Threshold.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void secumodDynamicSignaturesTuning(uint16_t period,
|
||||
uint8_t detectionThr, uint8_t resetThr) {
|
||||
|
||||
uint32_t dystune;
|
||||
|
||||
dystune = SECUMOD->SECUMOD_DYSTUNE & SECUMOD_DYSTUNE_NOPA;
|
||||
dystune |= SECUMOD_DYSTUNE_PERIOD(period);
|
||||
dystune |= SECUMOD_DYSTUNE_RX_ERROR_THRESHOLD(detectionThr);
|
||||
dystune |= SECUMOD_DYSTUNE_RX_OK_CORREL_NUMBER(resetThr);
|
||||
SECUMOD->SECUMOD_DYSTUNE = dystune;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable alarm regenerated periodically while intrusion is maintained.
|
||||
*
|
||||
* @param[in] enable periodic alarm while intrusion is maintained,
|
||||
* true: disable, false: enable.
|
||||
* @api
|
||||
*/
|
||||
void secumodPeriodicAlarm(bool enable) {
|
||||
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = SECUMOD->SECUMOD_DYSTUNE & ~SECUMOD_DYSTUNE_NOPA;
|
||||
if (!enable)
|
||||
tmp |= SECUMOD_DYSTUNE_NOPA;
|
||||
SECUMOD->SECUMOD_DYSTUNE = tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set access rights for secure RAM in SECUMOD.
|
||||
*
|
||||
* @param[in] region RAM region N,
|
||||
* for N = 0 ~ 5: RAM range (N)Kbyte ~ (N+1)Kbyte;
|
||||
* for N = 5: register bank 256bit.
|
||||
* @param rights 0: No access allowed;
|
||||
* 1: Only write access allowed;
|
||||
* 2: Only read access allowed;
|
||||
* 3: Read and write access allowed.
|
||||
* @api
|
||||
*/
|
||||
void secumodSetRamAccessRights(uint32_t region, uint8_t rights) {
|
||||
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = SECUMOD->SECUMOD_RAMACC & ~SECUMOD_RAMACC_RWx_Msk(region);
|
||||
SECUMOD->SECUMOD_RAMACC = tmp | (rights << SECUMOD_RAMACC_RWx_Pos(region));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the SECUMOD internal memory from the specified address
|
||||
*
|
||||
* @param[in] data Point to where the data read is stored
|
||||
* @param[in] addr memory address
|
||||
* @param[in] size The number of bytes to be read
|
||||
*
|
||||
* @return Bytes read
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint32_t secumodReadInternalMemory(uint8_t *data, uint32_t addr, uint32_t size) {
|
||||
|
||||
uint32_t i;
|
||||
uint32_t region;
|
||||
uint32_t count;
|
||||
|
||||
if (addr >= ((uint32_t)SECURAM))
|
||||
addr -= ((uint32_t)SECURAM);
|
||||
|
||||
secumodMemReady();
|
||||
|
||||
for (i = 0; i < size; i += count) {
|
||||
region = (addr + i) >> 10;
|
||||
if ((SECUMOD_RAMACC_RWx_NO_ACCESS(region) ==
|
||||
(SECUMOD->SECUMOD_RAMACC & SECUMOD_RAMACC_RWx_Msk(region))) ||
|
||||
(SECUMOD_RAMACC_RWx_WR_ACCESS(region) ==
|
||||
(SECUMOD->SECUMOD_RAMACC & SECUMOD_RAMACC_RWx_Msk(region)))) {
|
||||
break;
|
||||
}
|
||||
count = size;
|
||||
if (((region + 1) << 10 ) <= (addr + i + size)) {
|
||||
size = ((region + 1) << 10) - (addr + i);
|
||||
}
|
||||
memcpy(data + i, (uint8_t *)(((uint32_t)SECURAM) + addr + i), count);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data to the SECUMOD internal memory from the specified address
|
||||
*
|
||||
* @param[in] data Pointer to the data to be written
|
||||
* @param[in] addr memory address
|
||||
* @param[in] size The number of bytes to be be written
|
||||
*
|
||||
* @return Bytes written
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint32_t secumodWriteInternalMemory(uint8_t *data, uint32_t addr, uint32_t size) {
|
||||
|
||||
uint32_t i;
|
||||
uint32_t region;
|
||||
uint32_t count;
|
||||
|
||||
if (addr >= ((uint32_t)SECURAM))
|
||||
addr -= ((uint32_t)SECURAM);
|
||||
|
||||
secumodMemReady();
|
||||
|
||||
for (i = 0; i < size; i += count) {
|
||||
region = (addr + i) >> 10;
|
||||
if ((SECUMOD_RAMACC_RWx_NO_ACCESS(region) ==
|
||||
(SECUMOD->SECUMOD_RAMACC & SECUMOD_RAMACC_RWx_Msk(region))) ||
|
||||
(SECUMOD_RAMACC_RWx_RD_ACCESS(region) ==
|
||||
(SECUMOD->SECUMOD_RAMACC & SECUMOD_RAMACC_RWx_Msk(region)))) {
|
||||
break;
|
||||
}
|
||||
count = size;
|
||||
if (((region + 1) << 10 ) <= (addr + i + size)) {
|
||||
size = ((region + 1) << 10) - (addr + i);
|
||||
}
|
||||
memcpy((uint8_t *)(((uint32_t)SECURAM) + addr + i), data + i, count);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif /* SAMA_USE_SECUMOD */
|
||||
|
||||
/** @} */
|
|
@ -1,572 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_secumod.h
|
||||
* @brief SAMA SECUMOD support macros and structures.
|
||||
*
|
||||
* @addtogroup SAMA5D2x_SECUMOD
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_SECUMOD_LLD_H
|
||||
#define SAMA_SECUMOD_LLD_H
|
||||
|
||||
/**
|
||||
* @brief Using the SECUMOD driver.
|
||||
*/
|
||||
#if !defined(SAMA_USE_SECUMOD) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_SECUMOD FALSE
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_SECUMOD || defined(__DOXYGEN__)
|
||||
|
||||
#include <string.h>
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name RAM ACCESS mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief No access allowed.
|
||||
*/
|
||||
#define RAMACC_NO_ACCESS 0x0U
|
||||
|
||||
/**
|
||||
* @brief Only write access allowed.
|
||||
*/
|
||||
#define RAMACC_WR_ACCESS 0x1U
|
||||
|
||||
/**
|
||||
* @brief Only read access allowed.
|
||||
*/
|
||||
#define RAMACC_RD_ACCESS 0x2U
|
||||
|
||||
/**
|
||||
* @brief Read and Write access allowed.
|
||||
*/
|
||||
#define RAMACC_WR_RD_ACCESS 0x3U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SOURCE INTERRUPT macros
|
||||
* @{
|
||||
*/
|
||||
/*
|
||||
* @brief Shield Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_SHLDM (0x1u << 0)
|
||||
|
||||
/*
|
||||
* @brief Double Frequency Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_DBLFM (0x1u << 1)
|
||||
|
||||
/*
|
||||
* @brief Test Pin Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_TST (0x1u << 2)
|
||||
|
||||
/*
|
||||
* @brief JTAG Pins Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_JTAG (0x1u << 3)
|
||||
|
||||
/*
|
||||
* @brief Master Clock Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_MCKM (0x1u << 5)
|
||||
|
||||
/*
|
||||
* @brief Low Temperature Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_TPML (0x1u << 6)
|
||||
|
||||
/*
|
||||
* @brief High Temperature Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_TPMH (0x1u << 7)
|
||||
|
||||
/*
|
||||
* @brief Low VDDBU Voltage Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_VDDBUL (0x1u << 10)
|
||||
|
||||
/*
|
||||
* @brief High VDDBU Voltage Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_VDDBUH (0x1u << 11)
|
||||
|
||||
/*
|
||||
* @brief Low VDDCORE Voltage Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_VDDCOREL (0x1u << 12)
|
||||
|
||||
/*
|
||||
* @brief High VDDCORE Voltage Monitor Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_VDDCOREH (0x1u << 13)
|
||||
|
||||
/*
|
||||
* @brief PIOBUx Intrusion Detector Protection Interrupt Source.
|
||||
*/
|
||||
#define SECUMOD_DET0 (0x1u << 16)
|
||||
#define SECUMOD_DET1 (0x1u << 17)
|
||||
#define SECUMOD_DET2 (0x1u << 18)
|
||||
#define SECUMOD_DET3 (0x1u << 19)
|
||||
#define SECUMOD_DET4 (0x1u << 20)
|
||||
#define SECUMOD_DET5 (0x1u << 21)
|
||||
#define SECUMOD_DET6 (0x1u << 22)
|
||||
#define SECUMOD_DET7 (0x1u << 23)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name RAM STATUS mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief No access violation occurred.
|
||||
*/
|
||||
#define RAMACCSR_NO_VIOLATION 0x0U
|
||||
|
||||
/**
|
||||
* @brief Write access violation occurred.
|
||||
*/
|
||||
#define RAMACCSR_WR_VIOLATION 0x1U
|
||||
|
||||
/**
|
||||
* @brief Read access violation occurred.
|
||||
*/
|
||||
#define RAMACCSR_RD_VIOLATION 0x2U
|
||||
|
||||
/**
|
||||
* @brief Read and Write access violation occurred.
|
||||
*/
|
||||
#define RAMACCSR_WR_RD_VIOLATION 0x3U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SCRAMB mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief SCRAMB ENABLE.
|
||||
*/
|
||||
#define SCRAMB_ENABLE 0x1U
|
||||
|
||||
/**
|
||||
* @brief SCRAMB DISABLE.
|
||||
*/
|
||||
#define SCRAMB_DISABLE 0x2U
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* @brief RAM regions of SECUMOD
|
||||
*/
|
||||
#define SECUMOD_RAM_REGIONS 6
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief SECUMOD interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SECUMOD_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SECUMOD_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SECURAM interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_SECURAM_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_SECURAM_IRQ_PRIORITY 7
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
SEC_UNINIT = 0, /**< Not initialized. */
|
||||
SEC_STOP = 1, /**< Stopped. */
|
||||
SEC_ACTIVE = 2 /**< Active. */
|
||||
} secstate_t;
|
||||
|
||||
/**
|
||||
* @brief Type of an SECUMOD event.
|
||||
*/
|
||||
typedef enum {
|
||||
SEC_EVENT_SHLDM = 0, /* Triggered on Shield Monitor. */
|
||||
SEC_EVENT_DBLFM = 1, /* Triggered on Double Frequency Monitor. */
|
||||
SEC_EVENT_TST = 2, /* Triggered on Test Pin Monitor. */
|
||||
SEC_EVENT_JTAG = 3, /* Triggered on JTAG Pins Monitor. */
|
||||
SEC_EVENT_MCKM = 4, /* Triggered on Master Clock Monitor. */
|
||||
SEC_EVENT_TPML = 5, /* Triggered on Low Temperature Monitor. */
|
||||
SEC_EVENT_TPMH = 6, /* Triggered on High Temperature Monitor. */
|
||||
SEC_EVENT_VDDBUL = 7, /* Triggered on Low VDDBU Voltage Monitor. */
|
||||
SEC_EVENT_VDDBUH = 8, /* Triggered on High VDDBU Voltage Monitor. */
|
||||
SEC_EVENT_VDDCOREL = 9, /* Triggered on Low VDDCORE Voltage Monitor. */
|
||||
SEC_EVENT_VDDCOREH = 10, /* Triggered on High VDDCORE Voltage Monitor. */
|
||||
SEC_EVENT_PIOBU0 = 11, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU1 = 12, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU2 = 13, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU3 = 14, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU4 = 15, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU5 = 16, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU6 = 17, /* Triggered on PIOBUx intrusion. */
|
||||
SEC_EVENT_PIOBU7 = 18 /* Triggered on PIOBUx intrusion. */
|
||||
} secevent_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an SEC driver.
|
||||
*/
|
||||
typedef struct SECDriver SECDriver;
|
||||
|
||||
/**
|
||||
* @brief SECURAM notification callback type.
|
||||
*
|
||||
* @param[in] secp pointer to a @p SECDriver object
|
||||
*/
|
||||
typedef void (*securam_callback_t)(SECDriver *secp);
|
||||
|
||||
/**
|
||||
* @brief SECUMOD notification callback type.
|
||||
*
|
||||
* @param[in] secp pointer to a @p SECDriver object
|
||||
*/
|
||||
typedef void (*secumod_callback_t)(SECDriver *secp, secevent_t event);
|
||||
|
||||
/**
|
||||
* @brief SECUMOD erase callback type.
|
||||
*
|
||||
* @param[in] secp pointer to a @p SECDriver object
|
||||
*/
|
||||
typedef void (*erased_callback_t)(SECDriver *secp);
|
||||
|
||||
/**
|
||||
* @brief Type of RAM access mode.
|
||||
*/
|
||||
typedef uint32_t ram_access_mode_t;
|
||||
|
||||
/**
|
||||
* @brief PIOBU configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* @brief PIOBU pin's index
|
||||
*/
|
||||
uint32_t pinIndex:3;
|
||||
/*
|
||||
* @brief alarm filter value
|
||||
*/
|
||||
uint32_t afv:4;
|
||||
/*
|
||||
* @brief reset filter value
|
||||
*/
|
||||
uint32_t rfv:4;
|
||||
/*
|
||||
* @brief I/O line mode
|
||||
* @note 0: pure input, 1: enabled in output
|
||||
*/
|
||||
uint32_t mode:1;
|
||||
/*
|
||||
* @brief Configure the I/O line in output mode
|
||||
* @note 0: clear, 1: set
|
||||
*/
|
||||
uint32_t outputLevel:1;
|
||||
/*
|
||||
* @brief programmable pull-up state
|
||||
* @note 0: none, 1: pull-up; 2: pull-down; 3: reserved
|
||||
*/
|
||||
uint32_t pullUpState:2;
|
||||
/*
|
||||
* @brief Pull-up/Down Scheduled:
|
||||
* @note 0: no; 1: yes
|
||||
*/
|
||||
uint32_t scheduled:1;
|
||||
/*
|
||||
* @brief switch input default state
|
||||
*/
|
||||
uint32_t inputDefaultLevel:1;
|
||||
/*
|
||||
* @brief Mode of detection intrusion.
|
||||
* @note 0: static, 1: dynamic
|
||||
*/
|
||||
uint32_t dynamic:1;
|
||||
/*
|
||||
* @brief filter for dynamic signatures input
|
||||
* @note 0: 3 stages majority vote, 1: 5 stages
|
||||
*/
|
||||
uint32_t filter3_5:1;
|
||||
} PIOBUConfig;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief RAM Access Right
|
||||
*/
|
||||
ram_access_mode_t mode;
|
||||
/* End of the mandatory fields.*/
|
||||
} RAMAccessConfig;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note It could be empty on some architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Callback for memory violation
|
||||
*/
|
||||
securam_callback_t securam_callback;
|
||||
/**
|
||||
* @brief Callback after memory erasing
|
||||
*/
|
||||
erased_callback_t erased_callback;
|
||||
/**
|
||||
* @brief lenght of PIOBUConfig array
|
||||
* @note Number of pads to configure
|
||||
*/
|
||||
size_t length;
|
||||
/**
|
||||
* @brief pointer to PIOBUConfig array
|
||||
*/
|
||||
PIOBUConfig *list;
|
||||
/**
|
||||
* @brief RAM Access Rights
|
||||
*/
|
||||
RAMAccessConfig region[SECUMOD_RAM_REGIONS];
|
||||
/**
|
||||
* @brief SECUMOD CR register initialization data.
|
||||
*/
|
||||
uint32_t cr;
|
||||
/**
|
||||
* @brief SECUMOD JTAGCR register initialization data.
|
||||
*/
|
||||
uint32_t jtagcr;
|
||||
} SECConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a SEC driver.
|
||||
*/
|
||||
struct SECDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
secstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const SECConfig *config;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the SECUMOD registers block.
|
||||
*/
|
||||
Secumod *sec;
|
||||
/**
|
||||
* @brief Callback pointer.
|
||||
*/
|
||||
secumod_callback_t secumod_callback;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Switch to Backup Mode.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSwitch2BackupMode() { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_BACKUP; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Switch to Normal Mode.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSwitch2NormalMode() { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_NORMAL; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start clear content of SECUMOD internal RAM 4Kbyte and 256bits.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSoftwareProtection() { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_SWPROT; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable Auto-Backup.
|
||||
*
|
||||
* @param[in] enable Enable auto-backup if true, disable otherwise.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetAutoBackup(enable) { \
|
||||
if (enable) { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_AUTOBKP_AUTO_SWITCH; \
|
||||
} \
|
||||
else { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_AUTOBKP_SW_SWITCH; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable Memory Scrambling.
|
||||
*
|
||||
* @param[in] enable Enable memory scrambling if true, disable otherwise.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetScrambling(enable) { \
|
||||
if (enable) { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_SCRAMB_ENABLE; \
|
||||
} \
|
||||
else { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_SCRAMB_DISABLE; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggle normal or backup protection registers appear and disappear.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodToggleProtectionReg() { \
|
||||
SECUMOD->SECUMOD_CR = SECUMOD_CR_KEY_TOGGLE; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set scrambling key for secure RAM in SECUMOD.
|
||||
*
|
||||
* @param[in] key Scrambling key.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetScramblingKey(key) { \
|
||||
SECUMOD->SECUMOD_SCRKEY = key; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get scrambling key for secure RAM in SECUMOD.
|
||||
*
|
||||
* @return Scrambling key.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodGetScramblingKey() { \
|
||||
SECUMOD->SECUMOD_SCRKEY; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set protections enabled in backup mode.
|
||||
*
|
||||
* @note Make sure registers appears before call this function, to toggle the
|
||||
* appearance of the registers using secumodToggleProtectionReg().
|
||||
*
|
||||
* @param[in] sources Bitwise OR of protections.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetBackupModeProtections(sources) { \
|
||||
SECUMOD->SECUMOD_BMPR = sources; \
|
||||
if (SECUMOD->SECUMOD_BMPR != sources) { \
|
||||
secumodToggleProtectionReg(); \
|
||||
SECUMOD->SECUMOD_BMPR = sources; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set protections enabled in normal mode.
|
||||
*
|
||||
* @note Make sure registers appears before call this function, to toggle the
|
||||
* appearance of the registers using secumodToggleProtectionReg().
|
||||
*
|
||||
* @param[in] sources Bitwise OR of protections.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetNormalModeProtections(sources) { \
|
||||
SECUMOD->SECUMOD_NMPR = sources; \
|
||||
if (SECUMOD->SECUMOD_NMPR != sources) { \
|
||||
secumodToggleProtectionReg(); \
|
||||
SECUMOD->SECUMOD_NMPR = sources; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set protection sources which can cause wake up signal generated.
|
||||
*
|
||||
* @param[in] sources Bitwise OR of protection sources.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodSetWakeupProtections(sources) { \
|
||||
SECUMOD->SECUMOD_WKPR = sources; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait availability status of memory.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define secumodMemReady() { \
|
||||
while (!(SECUMOD->SECUMOD_RAMRDY & SECUMOD_RAMRDY_READY)); \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
extern SECDriver SECD0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void secInit(void);
|
||||
void secObjectInit(SECDriver *secp);
|
||||
void secStart(SECDriver *secp, const SECConfig *config);
|
||||
void secStop(SECDriver *secp);
|
||||
void secSetCallback(SECDriver *secp, uint32_t sources, secumod_callback_t callback);
|
||||
void secumodSetJtagProtection(bool reset, uint8_t permissions, bool ack);
|
||||
void secumodDynamicSignaturesTuning(uint16_t period, uint8_t detectionThr, uint8_t resetThr);
|
||||
void secumodPeriodicAlarm(bool enable);
|
||||
void secumodSetRamAccessRights(uint32_t region, uint8_t rights);
|
||||
uint32_t secumodReadInternalMemory(uint8_t *data, uint32_t addr, uint32_t size);
|
||||
uint32_t secumodWriteInternalMemory(uint8_t *data, uint32_t addr, uint32_t size);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_SECUMOD */
|
||||
|
||||
#endif /* SAMA_SECUMOD_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,575 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_tc_lld.c
|
||||
* @brief SAMA TC support code.
|
||||
*
|
||||
* @addtogroup TC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if SAMA_USE_TC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tcp pointer to a TC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcEnableWP(tcp) { \
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection on TC registers block.
|
||||
*
|
||||
* @param[in] tcp pointer to a TC register block
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define tcDisableWP(tcp) { \
|
||||
tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD; \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief TCD0 driver identifier.
|
||||
* @note The driver TCD0 allocates the timer TC0 when enabled.
|
||||
*/
|
||||
#if SAMA_USE_TC0 || defined(__DOXYGEN__)
|
||||
TCDriver TCD0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 driver identifier.
|
||||
* @note The driver TCD1 allocates the timer TC1 when enabled.
|
||||
*/
|
||||
#if SAMA_USE_TC1 || defined(__DOXYGEN__)
|
||||
TCDriver TCD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Common IRQ handler.
|
||||
* @note It is assumed that the various sources are only activated if the
|
||||
* associated callback pointer is not equal to @p NULL in order to not
|
||||
* perform an extra check in a potentially critical interrupt handler.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_serve_interrupt(TCDriver *tcp) {
|
||||
uint32_t sr, imr, i;
|
||||
|
||||
for (i = 0; i < TC_CHANNELS; i++) {
|
||||
sr = tcp->tim->TC_CHANNEL[i].TC_SR;
|
||||
imr = tcp->tim->TC_CHANNEL[i].TC_IMR;
|
||||
if (((sr & TC_SR_CPCS) != 0) && ((imr & TC_IMR_CPCS) != 0) &&
|
||||
(tcp->config->channels[i].callback != NULL)) {
|
||||
tcp->config->channels[i].callback(tcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_USE_TC0 || defined(__DOXYGEN__)
|
||||
#if !defined(SAMA_TC0_SUPPRESS_ISR)
|
||||
/**
|
||||
* @brief TC0 interrupt handler.
|
||||
* @note It is assumed that this interrupt is only activated if the callback
|
||||
* pointer is not equal to @p NULL in order to not perform an extra
|
||||
* check in a potentially critical interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TC0_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
tc_lld_serve_interrupt(&TCD0);
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* !defined(SAMA_TC0_SUPPRESS_ISR) */
|
||||
#endif /* SAMA_USE_TC0 */
|
||||
|
||||
#if SAMA_USE_TC1 || defined(__DOXYGEN__)
|
||||
#if !defined(SAMA_TC1_SUPPRESS_ISR)
|
||||
/**
|
||||
* @brief TC1 interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(SAMA_TC1_HANDLER) {
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
tc_lld_serve_interrupt(&TCD1);
|
||||
aicAckInt();
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
#endif /* !defined(SAMA_TC1_SUPPRESS_ISR) */
|
||||
#endif /* SAMA_USE_TC1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level TC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_init(void) {
|
||||
|
||||
#if SAMA_USE_TC0
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC0, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
tcObjectInit(&TCD0);
|
||||
TCD0.channels = TC_CHANNELS;
|
||||
TCD0.tim = TC0;
|
||||
TCD0.clock = SAMA_TC0CLK;
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
#if SAMA_HAL_IS_SECURE
|
||||
mtxConfigPeriphSecurity(MATRIX1, ID_TC1, SECURE_PER);
|
||||
#endif /* SAMA_HAL_IS_SECURE */
|
||||
/* Driver initialization.*/
|
||||
tcObjectInit(&TCD1);
|
||||
TCD1.channels = TC_CHANNELS;
|
||||
TCD1.tim = TC1;
|
||||
TCD1.clock = SAMA_TC1CLK;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_start(TCDriver *tcp) {
|
||||
uint32_t rc = 0;
|
||||
|
||||
if (tcp->state == TC_STOP) {
|
||||
/* Clock activation.*/
|
||||
#if SAMA_USE_TC0
|
||||
if (&TCD0 == tcp) {
|
||||
pmcEnableTC0();
|
||||
#if !defined(SAMA_TC0_SUPPRESS_ISR)
|
||||
aicSetSourcePriority(ID_TC0, SAMA_TC0_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC0, SAMA_TC0_HANDLER);
|
||||
aicEnableInt(ID_TC0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
if (&TCD1 == tcp) {
|
||||
pmcEnableTC1();
|
||||
#if !defined(SAMA_TC1_SUPPRESS_ISR)
|
||||
aicSetSourcePriority(ID_TC1, SAMA_TC1_IRQ_PRIORITY);
|
||||
aicSetSourceHandler(ID_TC1, SAMA_TC1_HANDLER);
|
||||
aicEnableInt(ID_TC1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* Disable Write Protection */
|
||||
tcDisableWP(tcp->tim);
|
||||
/* Output enables*/
|
||||
switch (tcp->config->channels[0].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[0].frequency);
|
||||
tcp->tim->TC_CHANNEL[0].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[0].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
switch (tcp->config->channels[1].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[1].frequency);
|
||||
tcp->tim->TC_CHANNEL[1].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[1].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[1].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[1].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
switch (tcp->config->channels[2].mode & TC_OUTPUT_MASK) {
|
||||
case TC_OUTPUT_ACTIVE:
|
||||
rc = (tcp->clock) / (tcp->config->channels[2].frequency);
|
||||
tcp->tim->TC_CHANNEL[2].TC_EMR = TC_EMR_NODIVCLK;
|
||||
tcp->tim->TC_CHANNEL[2].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
|
||||
TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
|
||||
|
||||
tcp->tim->TC_CHANNEL[2].TC_RC = TC_RC_RC(rc);
|
||||
tcp->tim->TC_CHANNEL[2].TC_SR; /* Clear pending IRQs. */
|
||||
default:
|
||||
;
|
||||
}
|
||||
/* Enable Write Protection */
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_stop(TCDriver *tcp) {
|
||||
|
||||
/* If in ready state then disables the TC clock.*/
|
||||
if (tcp->state == TC_READY) {
|
||||
#if SAMA_USE_TC0
|
||||
if (&TCD0 == tcp) {
|
||||
aicDisableInt(ID_TC0);
|
||||
pmcDisableTC0();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1
|
||||
if (&TCD1 == tcp) {
|
||||
aicDisableInt(ID_TC1);
|
||||
pmcDisableTC1();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note The function has effect at the next cycle start.
|
||||
* @note Channel notification is not enabled.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_enable_channel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width) {
|
||||
/* Disable Write Protection */
|
||||
tcDisableWP(tcp->tim);
|
||||
|
||||
/* Changing channel duty cycle on the fly.*/
|
||||
uint32_t rc = tcp->tim->TC_CHANNEL[channel].TC_RC;
|
||||
tcp->tim->TC_CHANNEL[channel].TC_RA = TC_RA_RA((100 - width) * rc / 100);
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKEN;
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_SWTRG;
|
||||
|
||||
/* Enable Write Protection */
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel and its notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note The function has effect at the next cycle start.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_disable_channel(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKDIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_enable_channel_notification(TCDriver *tcp,
|
||||
tcchannel_t channel) {
|
||||
tcp->tim->TC_CHANNEL[channel].TC_IER |= TC_IER_CPCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void tc_lld_disable_channel_notification(TCDriver *tcp,
|
||||
tcchannel_t channel) {
|
||||
|
||||
tcp->tim->TC_CHANNEL[channel].TC_IDR |= TC_IDR_CPCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes TC channel's frequency.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel must be enabled using @p tcEnableChannel().
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
*/
|
||||
|
||||
void tcChangeChannelFrequency(TCDriver *tcp,
|
||||
tcchannel_t channel,uint32_t frequency) {
|
||||
tcDisableWP(tcp->tim);
|
||||
uint32_t rc =(tcp->clock) / (frequency);
|
||||
tcp->tim->TC_CHANNEL[channel].TC_RC = TC_RC_RC(rc);
|
||||
tcEnableWP(tcp->tim);
|
||||
}
|
||||
/**
|
||||
* @brief TC Driver initialization.
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void tcInit(void) {
|
||||
|
||||
tc_lld_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the standard part of a @p TCDriver structure.
|
||||
*
|
||||
* @param[out] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void tcObjectInit(TCDriver *tcp) {
|
||||
|
||||
tcp->state = TC_STOP;
|
||||
tcp->config = NULL;
|
||||
tcp->enabled = 0;
|
||||
tcp->channels = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] config pointer to a @p TCConfig object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcStart(TCDriver *tcp, const TCConfig *config) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (config != NULL));
|
||||
|
||||
osalSysLock();
|
||||
osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
|
||||
"invalid state");
|
||||
tcp->config = config;
|
||||
tc_lld_start(tcp);
|
||||
tcp->enabled = 0;
|
||||
tcp->state = TC_READY;
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the TC peripheral.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcStop(TCDriver *tcp) {
|
||||
|
||||
osalDbgCheck(tcp != NULL);
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
|
||||
"invalid state");
|
||||
|
||||
tc_lld_stop(tcp);
|
||||
tcp->enabled = 0;
|
||||
tcp->config = NULL;
|
||||
tcp->state = TC_STOP;
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcEnableChannel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
|
||||
tcEnableChannelI(tcp, channel, width);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel and its notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcDisableChannel(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
|
||||
tcDisableChannelI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
|
||||
"channel not enabled");
|
||||
osalDbgAssert(tcp->config->channels[channel].callback != NULL,
|
||||
"undefined channel callback");
|
||||
|
||||
tcEnableChannelNotificationI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
|
||||
|
||||
osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
|
||||
|
||||
osalSysLock();
|
||||
|
||||
osalDbgAssert(tcp->state == TC_READY, "not ready");
|
||||
osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
|
||||
"channel not enabled");
|
||||
osalDbgAssert(tcp->config->channels[channel].callback != NULL,
|
||||
"undefined channel callback");
|
||||
|
||||
tcDisableChannelNotificationI(tcp, channel);
|
||||
|
||||
osalSysUnlock();
|
||||
}
|
||||
|
||||
#endif /* SAMA_USE_TC */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SAMA5D2x/sama_tc_lld.h
|
||||
* @brief SAMA TC subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup TC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SAMA_TC_LLD_H
|
||||
#define SAMA_TC_LLD_H
|
||||
|
||||
/**
|
||||
* @brief Using the TC driver.
|
||||
*/
|
||||
#if !defined(SAMA_USE_TC) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_TC FALSE
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of TC channels per TC driver.
|
||||
*/
|
||||
#define TC_CHANNELS TCCHANNEL_NUMBER
|
||||
|
||||
/**
|
||||
* @name TC output mode macros
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Standard output modes mask.
|
||||
*/
|
||||
#define TC_OUTPUT_MASK 0x0FU
|
||||
|
||||
/**
|
||||
* @brief Output not driven, callback only.
|
||||
*/
|
||||
#define TC_OUTPUT_DISABLED 0x00U
|
||||
|
||||
/**
|
||||
* @brief Output active.
|
||||
*/
|
||||
#define TC_OUTPUT_ACTIVE 0x01U
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Driver state machine possible states.
|
||||
*/
|
||||
typedef enum {
|
||||
TC_UNINIT = 0, /**< Not initialized. */
|
||||
TC_STOP = 1, /**< Stopped. */
|
||||
TC_READY = 2 /**< Ready. */
|
||||
} tcstate_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing a TC driver.
|
||||
*/
|
||||
typedef struct TCDriver TCDriver;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC notification callback.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
*/
|
||||
typedef void (*tccallback_t)(TCDriver *tcp);
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief TCD0 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TCD0 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(SAMA_USE_TC0) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_TC0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for TCD1 is included.
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(SAMA_USE_TC1) || defined(__DOXYGEN__)
|
||||
#define SAMA_USE_TC1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD0 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_TC0_IRQ_PRIORITY 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCD1 interrupt priority level setting.
|
||||
*/
|
||||
#if !defined(SAMA_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||
#define SAMA_TC1_IRQ_PRIORITY 2
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Configuration checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !SAMA_USE_TC0 && !SAMA_USE_TC1
|
||||
#error "TC driver activated but no TC peripheral assigned"
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of TCx units.*/
|
||||
#if SAMA_USE_TC0
|
||||
#if defined(SAMA_TC0_IS_USED)
|
||||
#error "TC0 is already used"
|
||||
#else
|
||||
#define SAMA_TC0_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Checks on allocation of TCx units.*/
|
||||
#if SAMA_USE_TC1
|
||||
#if defined(SAMA_TC1_IS_USED)
|
||||
#error "TC1 is already used"
|
||||
#else
|
||||
#define SAMA_TC1_IS_USED
|
||||
#endif
|
||||
#endif
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a TC mode.
|
||||
*/
|
||||
typedef uint32_t tcmode_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC channel.
|
||||
*/
|
||||
typedef uint8_t tcchannel_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a channels mask.
|
||||
*/
|
||||
typedef uint32_t tcchnmsk_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC counter.
|
||||
*/
|
||||
typedef uint32_t tccnt_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC driver channel configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channel active logic level.
|
||||
*/
|
||||
tcmode_t mode;
|
||||
/**
|
||||
* @brief Timer clock in Hz.
|
||||
* @note The low level can use assertions in order to catch invalid
|
||||
* frequency specifications.
|
||||
*/
|
||||
uint32_t frequency;
|
||||
/**
|
||||
* @brief Channel callback pointer.
|
||||
* @note This callback is invoked on the channel compare event. If set to
|
||||
* @p NULL then the callback is disabled.
|
||||
*/
|
||||
tccallback_t callback;
|
||||
/* End of the mandatory fields.*/
|
||||
} TCChannelConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of a TC driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Channels configurations.
|
||||
*/
|
||||
TCChannelConfig channels[TC_CHANNELS];
|
||||
/* End of the mandatory fields.*/
|
||||
} TCConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a TC driver.
|
||||
*/
|
||||
struct TCDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
tcstate_t state;
|
||||
/**
|
||||
* @brief Current driver configuration data.
|
||||
*/
|
||||
const TCConfig *config;
|
||||
/**
|
||||
* @brief Mask of the enabled channels.
|
||||
*/
|
||||
tcchnmsk_t enabled;
|
||||
/**
|
||||
* @brief Number of channels in this instance.
|
||||
*/
|
||||
tcchannel_t channels;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Timer base clock.
|
||||
*/
|
||||
uint32_t clock;
|
||||
/**
|
||||
* @brief Pointer to the TCx registers block.
|
||||
*/
|
||||
Tc *tim;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @brief Enables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is active using the specified configuration.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
* @param[in] width TC pulse width as clock pulses number
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcEnableChannelI(tcp, channel, width) do { \
|
||||
(tcp)->enabled |= ((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
|
||||
tc_lld_enable_channel(tcp, channel, width); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Disables a TC channel.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @post The channel is disabled and its output line returned to the
|
||||
* idle state.
|
||||
* @note Depending on the hardware implementation this function has
|
||||
* effect starting on the next cycle (recommended implementation)
|
||||
* or immediately (fallback implementation).
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcDisableChannelI(tcp, channel) do { \
|
||||
(tcp)->enabled &= ~((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
|
||||
tc_lld_disable_channel(tcp, channel); \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @brief Returns a TC channel status.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcIsChannelEnabledI(tcp, channel) \
|
||||
(((tcp)->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)(channel))) != 0U)
|
||||
|
||||
/**
|
||||
* @brief Enables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already enabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcEnableChannelNotificationI(tcp, channel) \
|
||||
tc_lld_enable_channel_notification(tcp, channel)
|
||||
|
||||
/**
|
||||
* @brief Disables a channel de-activation edge notification.
|
||||
* @pre The TC unit must have been activated using @p tcStart().
|
||||
* @pre The channel must have been activated using @p tcEnableChannel().
|
||||
* @note If the notification is already disabled then the call has no effect.
|
||||
*
|
||||
* @param[in] tcp pointer to a @p TCDriver object
|
||||
* @param[in] channel TC channel identifier (0...channels-1)
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define tcDisableChannelNotificationI(tcp, channel) \
|
||||
tc_lld_disable_channel_notification(tcp, channel)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SAMA_USE_TC0 && !defined(__DOXYGEN__)
|
||||
extern TCDriver TCD0;
|
||||
#endif
|
||||
|
||||
#if SAMA_USE_TC1 && !defined(__DOXYGEN__)
|
||||
extern TCDriver TCD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void tcInit(void);
|
||||
void tcObjectInit(TCDriver *tcp);
|
||||
void tcStart(TCDriver *tcp, const TCConfig *config);
|
||||
void tcStop(TCDriver *tcp);
|
||||
void tcEnableChannel(TCDriver *tcp,
|
||||
tcchannel_t channel,
|
||||
tccnt_t width);
|
||||
void tcDisableChannel(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel);
|
||||
void tcChangeChannelFrequency(TCDriver *tcp, tcchannel_t channel, uint32_t frequency);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMA_USE_TC */
|
||||
|
||||
#endif /* SAMA_TC_LLD_H */
|
||||
|
||||
/** @} */
|
Loading…
Reference in New Issue