git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13269 27425a3e-05d8-49a3-a47f-9c15f0e5edd8

This commit is contained in:
Giovanni Di Sirio 2020-01-13 09:27:43 +00:00
parent e85ee4b43d
commit 575eaf312d
87 changed files with 0 additions and 31759 deletions

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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_ */

View File

@ -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 */
/** @} */

View File

@ -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_
/** @} */

View File

@ -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

View File

@ -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_ */

View File

@ -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 */
/** @} */

View File

@ -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_ */

View File

@ -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 */
/** @} */

View File

@ -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_ */

View File

@ -1,2 +0,0 @@
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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(&ETHD0.rdqueue, MSG_RESET);
#if MAC_USE_EVENTS
osalEventBroadcastFlagsI(&ETHD0.rdevent, 0);
#endif
osalSysUnlockFromISR();
}
if (isr & GMAC_ISR_TCOMP) {
/* Data Transmitted.*/
osalSysLockFromISR();
/* Clear Status Register */
GMAC0->GMAC_TSR = tsr;
osalThreadDequeueAllI(&ETHD0.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(&ETHD0);
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(&ETHD0);
#endif
#if defined(BOARD_PHY_RESET)
/* PHY board-specific reset procedure.*/
BOARD_PHY_RESET();
#else
/* PHY soft reset procedure.*/
mii_write(&ETHD0, MII_BMCR, BMCR_RESET);
#if defined(BOARD_PHY_RESET_DELAY)
osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
#endif
while (mii_read(&ETHD0, 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(&ETHD0, MII_BMCR, mii_read(&ETHD0, 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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
}
/** @} */

View File

@ -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_ */
/** @} */

View File

@ -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 */
}
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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)

View File

@ -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;
}
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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
}
/** @} */

View File

@ -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_ */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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);
}
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */