/*----------------------------------------------------------------------------*/ static enum result eepromInit(void *object, const void *configBase) { const struct EepromConfig * const config = configBase; struct Eeprom * const interface = object; if (!setDescriptor(0, interface)) return E_BUSY; interface->position = 0; interface->size = (uintptr_t)&_eeeprom - (uintptr_t)&_seeprom; interface->blocking = true; /* Enable clock to register interface and peripheral */ sysClockEnable(CLK_M4_EEPROM); /* Reset registers to default values */ sysResetEnable(RST_EEPROM); const uint32_t frequency = clockFrequency(MainClock); LPC_EEPROM->CLKDIV = (frequency + (EEPROM_CLOCK - 1)) / EEPROM_CLOCK - 1; LPC_EEPROM->INTENSET = INT_PROG_DONE; if (config) irqSetPriority(EEPROM_IRQ, config->priority); irqEnable(EEPROM_IRQ); return E_OK; }
/*----------------------------------------------------------------------------*/ static enum Result pinInterruptInit(void *object, const void *configBase) { const struct PinInterruptConfig * const config = configBase; assert(config); const struct Pin input = pinInit(config->pin); assert(pinValid(input)); /* Try to allocate a new channel */ struct PinInterrupt * const interrupt = object; const int channel = setInstance(interrupt); if (channel == -1) return E_BUSY; /* Configure the pin */ pinInput(input); pinSetPull(input, config->pull); interrupt->callback = 0; interrupt->channel = channel; interrupt->enabled = false; interrupt->event = config->event; interrupt->pin = input.data; const uint8_t index = interrupt->channel >> 2; const uint32_t mask = 1UL << interrupt->channel; /* Enable peripheral */ if (!sysClockStatus(CLK_PINT)) sysClockEnable(CLK_PINT); /* Select pin and port */ LPC_SYSCON->PINTSEL[index] = (LPC_SYSCON->PINTSEL[index] & ~PINTSEL_CHANNEL_MASK(channel)) | PINTSEL_CHANNEL(channel, input.data.port, input.data.offset); /* Configure interrupt as edge sensitive */ LPC_GPIO_INT->ISEL &= ~mask; /* Configure edge sensitivity options */ if (config->event == PIN_RISING || config->event == PIN_TOGGLE) LPC_GPIO_INT->SIENR = mask; if (config->event == PIN_FALLING || config->event == PIN_TOGGLE) LPC_GPIO_INT->SIENF = mask; #ifdef CONFIG_PM /* Interrupt will wake the controller from low-power modes */ LPC_SYSCON->STARTERP0 |= STARTERP0_PINT(interrupt->channel); #endif /* Configure interrupt priority, interrupt is disabled by default */ irqSetPriority(calcVector(interrupt->channel), config->priority); return E_OK; }
/*----------------------------------------------------------------------------*/ static enum Result canInit(void *object, const void *configBase) { const struct CanConfig * const config = configBase; assert(config); const struct CanBaseConfig baseConfig = { .rx = config->rx, .tx = config->tx, .channel = config->channel }; struct Can * const interface = object; enum Result res; /* Call base class constructor */ if ((res = CanBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->timer = config->timer; interface->mode = MODE_LISTENER; interface->sequence = 0; const size_t poolSize = config->rxBuffers + config->txBuffers; if (!pointerArrayInit(&interface->pool, poolSize)) return E_MEMORY; if (!pointerQueueInit(&interface->rxQueue, config->rxBuffers)) return E_MEMORY; if (!pointerQueueInit(&interface->txQueue, config->txBuffers)) return E_MEMORY; interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize); struct CanStandardMessage *message = interface->poolBuffer; for (size_t index = 0; index < poolSize; ++index) { pointerArrayPushBack(&interface->pool, message); ++message; } LPC_CAN_Type * const reg = interface->base.reg; reg->MOD = MOD_RM; /* Reset CAN */ reg->IER = 0; /* Disable Receive Interrupt */ reg->GSR = 0; /* Reset error counter */ interface->rate = config->rate; reg->BTR = calcBusTimings(interface, interface->rate); /* Activate Listen Only mode and enable local priority for transmit buffers */ reg->MOD = MOD_LOM | MOD_TPM; LPC_CANAF->AFMR = AFMR_AccBP; //FIXME #ifdef CONFIG_PLATFORM_NXP_CAN_PM if ((res = pmRegister(powerStateHandler, interface)) != E_OK) return res; #endif /* Enable interrupts on message reception and bus error */ reg->IER = IER_RIE | IER_EPIE | IER_BEIE | IER_TIE_MASK; irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_CAN_NO_DEINIT static void canDeinit(void *object) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; /* Disable all interrupts */ irqDisable(interface->base.irq); reg->IER = 0; #ifdef CONFIG_PLATFORM_NXP_CAN_PM pmUnregister(interface); #endif pointerQueueDeinit(&interface->txQueue); pointerQueueDeinit(&interface->rxQueue); pointerArrayDeinit(&interface->pool); CanBase->deinit(interface); } #endif /*----------------------------------------------------------------------------*/ static enum Result canSetCallback(void *object, void (*callback)(void *), void *argument) { struct Can * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result canGetParam(void *object, enum IfParameter parameter, void *data) { struct Can * const interface = object; switch (parameter) { case IF_AVAILABLE: *(size_t *)data = pointerQueueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = pointerQueueSize(&interface->txQueue); return E_OK; case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result canSetParam(void *object, enum IfParameter parameter, const void *data) { struct Can * const interface = object; switch ((enum CanParameter)parameter) { case IF_CAN_ACTIVE: changeMode(interface, MODE_ACTIVE); return E_OK; case IF_CAN_LISTENER: changeMode(interface, MODE_LISTENER); return E_OK; case IF_CAN_LOOPBACK: changeMode(interface, MODE_LOOPBACK); return E_OK; default: break; } switch (parameter) { case IF_RATE: { const uint32_t rate = *(const uint32_t *)data; changeRate(interface, rate); interface->rate = rate; return E_OK; } default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t canRead(void *object, void *buffer, size_t length) { assert(length % sizeof(struct CanStandardMessage) == 0); struct Can * const interface = object; struct CanStandardMessage *current = buffer; const struct CanStandardMessage * const last = (const void *)((uintptr_t)buffer + length); while (!pointerQueueEmpty(&interface->rxQueue) && current < last) { irqDisable(interface->base.irq); struct CanMessage * const input = pointerQueueFront(&interface->rxQueue); pointerQueuePopFront(&interface->rxQueue); memcpy(current, input, sizeof(*current)); pointerArrayPushBack(&interface->pool, input); irqEnable(interface->base.irq); ++current; } return (uintptr_t)current - (uintptr_t)buffer; }
/*----------------------------------------------------------------------------*/ static enum Result sdioInit(void *object, const void *configBase) { const struct SdmmcConfig * const config = configBase; assert(config); const struct DmaSdmmcConfig dmaConfig = { .burst = DMA_BURST_4, .number = 16, .parent = object }; const struct PinInterruptConfig finalizerConfig = { .pin = config->dat0, .event = PIN_RISING, .pull = PIN_NOPULL, .priority = config->priority }; const struct SdmmcBaseConfig baseConfig = { .clk = config->clk, .cmd = config->cmd, .dat0 = config->dat0, .dat1 = config->dat1, .dat2 = config->dat2, .dat3 = config->dat3 }; struct Sdmmc * const interface = object; enum Result res; assert(config->rate); interface->finalizer = init(PinInterrupt, &finalizerConfig); if (!interface->finalizer) return E_ERROR; interruptSetCallback(interface->finalizer, interruptHandler, interface); /* Call base class constructor */ if ((res = SdmmcBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->argument = 0; interface->callback = 0; interface->command = 0; interface->status = E_OK; LPC_SDMMC_Type * const reg = interface->base.reg; /* Reset specified blocks */ reg->CTRL = CTRL_CONTROLLER_RESET; while (reg->CTRL & CTRL_CONTROLLER_RESET); /* Enable interrupts */ reg->INTMASK = 0; reg->CTRL = CTRL_INT_ENABLE; irqSetPriority(interface->base.irq, config->priority); /* Clear pending interrupts */ reg->RINTSTS = INT_MASK; /* Set bus width */ reg->CTYPE = interface->base.wide ? CTYPE_CARD_WIDTH0_4BIT : 0; /* Set default block size */ reg->BLKSIZ = DEFAULT_BLOCK_SIZE; /* Set default clock rate */ updateRate(interface, config->rate); /* Internal DMA controller should be initialized after interface setup */ interface->dma = init(DmaSdmmc, &dmaConfig); if (!interface->dma) return E_ERROR; return E_OK; } /*----------------------------------------------------------------------------*/ static void sdioDeinit(void *object) { struct Sdmmc * const interface = object; LPC_SDMMC_Type * const reg = interface->base.reg; deinit(interface->dma); /* Disable interrupts */ reg->CTRL &= ~CTRL_INT_ENABLE; deinit(interface->finalizer); SdmmcBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum Result sdioSetCallback(void *object, void (*callback)(void *), void *argument) { struct Sdmmc * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result sdioGetParam(void *object, enum IfParameter parameter, void *data) { struct Sdmmc * const interface = object; LPC_SDMMC_Type * const reg = interface->base.reg; /* Additional options */ switch ((enum SdioParameter)parameter) { case IF_SDIO_MODE: { *(uint8_t *)data = interface->base.wide ? SDIO_4BIT : SDIO_1BIT; return E_OK; } case IF_SDIO_RESPONSE: { const enum SdioResponse response = COMMAND_RESP_VALUE(interface->command); uint32_t * const buffer = data; if (response == SDIO_RESPONSE_LONG) { for (unsigned int index = 0; index < 4; ++index) buffer[index] = reg->RESP[index]; return E_OK; } else if (response == SDIO_RESPONSE_SHORT) { buffer[0] = reg->RESP[0]; return E_OK; } else return E_ERROR; } default: break; } switch (parameter) { case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; case IF_STATUS: return interface->status; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result sdioSetParam(void *object, enum IfParameter parameter, const void *data) { struct Sdmmc * const interface = object; LPC_SDMMC_Type * const reg = interface->base.reg; /* Additional options */ switch ((enum SdioParameter)parameter) { case IF_SDIO_EXECUTE: execute(interface); return E_BUSY; case IF_SDIO_ARGUMENT: interface->argument = *(const uint32_t *)data; return E_OK; case IF_SDIO_BLOCK_SIZE: { const size_t blockLength = *(const size_t *)data; if (blockLength < 0xFFFF) { reg->BLKSIZ = blockLength; return E_OK; } else return E_VALUE; } case IF_SDIO_COMMAND: interface->command = *(const uint32_t *)data; return E_OK; default: break; } switch (parameter) { case IF_RATE: return updateRate(interface, *(const uint32_t *)data); case IF_ZEROCOPY: return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t sdioRead(void *object, void *buffer, size_t length) { struct Sdmmc * const interface = object; LPC_SDMMC_Type * const reg = interface->base.reg; reg->BYTCNT = length; dmaAppend(interface->dma, buffer, 0, length); const enum Result res = dmaEnable(interface->dma); if (res == E_OK) { execute(interface); return length; } else { interface->status = res; return 0; } } /*----------------------------------------------------------------------------*/ static size_t sdioWrite(void *object, const void *buffer, size_t length) { struct Sdmmc * const interface = object; LPC_SDMMC_Type * const reg = interface->base.reg; reg->BYTCNT = length; dmaAppend(interface->dma, 0, buffer, length); const enum Result res = dmaEnable(interface->dma); if (res == E_OK) { execute(interface); return length; } else { interface->status = res; return 0; } }
/*----------------------------------------------------------------------------*/ static enum result spiInit(void *object, const void *configBase) { const struct SpiConfig * const config = configBase; const struct SspBaseConfig baseConfig = { .channel = config->channel, .miso = config->miso, .mosi = config->mosi, .sck = config->sck, .cs = 0 }; struct Spi * const interface = object; enum result res; /* Call base class constructor */ if ((res = SspBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->rate = config->rate; interface->blocking = true; LPC_SSP_Type * const reg = interface->base.reg; uint32_t controlValue = 0; /* Set frame size */ controlValue |= CR0_DSS(8); /* Set mode for the interface */ if (config->mode & 0x01) controlValue |= CR0_CPHA; if (config->mode & 0x02) controlValue |= CR0_CPOL; reg->CR0 = controlValue; /* Disable all interrupts */ reg->IMSC = 0; /* Try to set the desired data rate */ sspSetRate(object, interface->rate); #ifdef CONFIG_SSP_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif /* Enable the peripheral */ reg->CR1 = CR1_SSE; irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ static void spiDeinit(void *object) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; /* Disable the peripheral */ irqDisable(interface->base.irq); reg->CR1 = 0; #ifdef CONFIG_SSP_PM pmUnregister(interface); #endif SspBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result spiCallback(void *object, void (*callback)(void *), void *argument) { struct Spi * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result spiGet(void *object, enum ifOption option, void *data) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; switch (option) { case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; case IF_STATUS: return (interface->rxLeft || reg->SR & SR_BSY) ? E_BUSY : E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result spiSet(void *object, enum ifOption option, const void *data) { struct Spi * const interface = object; switch (option) { case IF_BLOCKING: interface->blocking = true; return E_OK; case IF_RATE: interface->rate = *(const uint32_t *)data; sspSetRate(object, interface->rate); return E_OK; case IF_ZEROCOPY: interface->blocking = false; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t spiRead(void *object, void *buffer, size_t length) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; if (!length) return 0; interface->rxBuffer = buffer; interface->txBuffer = 0; interface->rxLeft = interface->txLeft = length; /* Clear interrupt flags and enable interrupts */ reg->ICR = ICR_RORIC | ICR_RTIC; reg->IMSC = IMSC_RXIM | IMSC_RTIM; /* Initiate reception by setting pending interrupt flag */ irqSetPending(interface->base.irq); if (interface->blocking) { while (interface->rxLeft || reg->SR & SR_BSY) barrier(); } return length; } /*----------------------------------------------------------------------------*/ static size_t spiWrite(void *object, const void *buffer, size_t length) { struct Spi * const interface = object; LPC_SSP_Type * const reg = interface->base.reg; if (!length) return 0; interface->rxBuffer = 0; interface->txBuffer = buffer; interface->rxLeft = interface->txLeft = length; /* Clear interrupt flags and enable interrupts */ reg->ICR = ICR_RORIC | ICR_RTIC; reg->IMSC = IMSC_RXIM | IMSC_RTIM; /* Initiate transmission by setting pending interrupt flag */ irqSetPending(interface->base.irq); if (interface->blocking) { while (interface->rxLeft || reg->SR & SR_BSY) barrier(); } return length; }
/*----------------------------------------------------------------------------*/ static enum Result i2cInit(void *object, const void *configBase) { const struct I2cConfig * const config = configBase; assert(config); const struct I2cBaseConfig baseConfig = { .channel = config->channel, .scl = config->scl, .sda = config->sda }; struct I2c * const interface = object; enum Result res; /* Call base class constructor */ if ((res = I2cBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->address = 0; interface->callback = 0; interface->blocking = true; interface->sendStopBit = true; interface->state = STATE_IDLE; /* Rate should be initialized after block selection */ i2cSetRate(object, config->rate); LPC_I2C_Type * const reg = interface->base.reg; /* Clear all flags */ reg->CONCLR = CONCLR_AAC | CONCLR_SIC | CONCLR_STAC | CONCLR_I2ENC; /* Enable I2C interface */ reg->CONSET = CONSET_I2EN; irqSetPriority(interface->base.irq, config->priority); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_I2C_NO_DEINIT static void i2cDeinit(void *object) { struct I2c * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; reg->CONCLR = CONCLR_I2ENC; /* Disable I2C interface */ I2cBase->deinit(interface); } #endif /*----------------------------------------------------------------------------*/ static enum Result i2cSetCallback(void *object, void (*callback)(void *), void *argument) { struct I2c * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result i2cGetParam(void *object, enum IfParameter parameter, void *data) { struct I2c * const interface = object; switch (parameter) { case IF_STATUS: if (interface->blocking || interface->state != STATE_ERROR) return interface->state != STATE_IDLE ? E_BUSY : E_OK; else return E_ERROR; case IF_RATE: *(uint32_t *)data = i2cGetRate(object); return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result i2cSetParam(void *object, enum IfParameter parameter, const void *data) { struct I2c * const interface = object; /* Additional I2C parameters */ switch ((enum I2cParameter)parameter) { case IF_I2C_SENDSTOP: interface->sendStopBit = *(const bool *)data; return E_OK; default: break; } switch (parameter) { case IF_ADDRESS: if (*(const uint16_t *)data <= 127) { interface->address = *(const uint16_t *)data; return E_OK; } else return E_VALUE; case IF_BLOCKING: interface->blocking = true; return E_OK; case IF_RATE: i2cSetRate(object, *(const uint32_t *)data); return E_OK; case IF_ZEROCOPY: interface->blocking = false; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t i2cRead(void *object, void *buffer, size_t length) { struct I2c * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; if (!length) return 0; if (length > USHRT_MAX) length = USHRT_MAX; interface->rxLeft = length; interface->txLeft = 0; interface->rxBuffer = buffer; interface->txBuffer = 0; interface->state = STATE_ADDRESS; reg->CONSET = CONSET_STA; /* Continue previous transmission when Repeated Start is enabled */ if (reg->STAT == STATUS_DATA_TRANSMITTED_ACK) reg->CONCLR = CONCLR_SIC; irqEnable(interface->base.irq); if (interface->blocking) { while (interface->state != STATE_IDLE && interface->state != STATE_ERROR) barrier(); if (interface->state == STATE_ERROR) return 0; } return length; } /*----------------------------------------------------------------------------*/ static size_t i2cWrite(void *object, const void *buffer, size_t length) { struct I2c * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; if (!length) return 0; if (length > USHRT_MAX) length = USHRT_MAX; interface->rxLeft = 0; interface->txLeft = length; interface->rxBuffer = 0; interface->txBuffer = buffer; /* Stop previous transmission when Repeated Start is enabled */ if (reg->STAT == STATUS_DATA_TRANSMITTED_ACK) { reg->CONSET = CONSET_STO; reg->CONCLR = CONCLR_SIC; } /* * Start condition generation can be delayed when the bus is not free. * After Stop condition being transmitted Start will be generated * automatically. */ interface->state = STATE_ADDRESS; reg->CONSET = CONSET_STA; irqEnable(interface->base.irq); if (interface->blocking) { while (interface->state != STATE_IDLE && interface->state != STATE_ERROR) barrier(); if (interface->state == STATE_ERROR) return 0; } return length; }
/*----------------------------------------------------------------------------*/ static enum Result serialInit(void *object, const void *configBase) { const struct SerialConfig * const config = configBase; assert(config); const struct UartBaseConfig baseConfig = { .channel = config->channel, .rx = config->rx, .tx = config->tx }; struct Serial * const interface = object; struct UartRateConfig rateConfig; enum Result res; /* Call base class constructor */ if ((res = UartBase->init(object, &baseConfig)) != E_OK) return res; if ((res = uartCalcRate(object, config->rate, &rateConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->rate = config->rate; if (!byteQueueInit(&interface->rxQueue, config->rxLength)) return E_MEMORY; if (!byteQueueInit(&interface->txQueue, config->txLength)) return E_MEMORY; LPC_UART_Type * const reg = interface->base.reg; /* Set 8-bit length */ reg->LCR = LCR_WORD_8BIT; /* Enable FIFO and set RX trigger level */ reg->FCR = (reg->FCR & ~FCR_RX_TRIGGER_MASK) | FCR_ENABLE | FCR_RX_TRIGGER(RX_TRIGGER_LEVEL_8); /* Enable RBR and THRE interrupts */ reg->IER = IER_RBR | IER_THRE; /* Transmitter is enabled by default thus TER register is left untouched */ uartSetParity(object, config->parity); uartSetRate(object, rateConfig); #ifdef CONFIG_PLATFORM_NXP_UART_PM if ((res = pmRegister(powerStateHandler, interface)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_UART_NO_DEINIT static void serialDeinit(void *object) { struct Serial * const interface = object; irqDisable(interface->base.irq); #ifdef CONFIG_PLATFORM_NXP_UART_PM pmUnregister(interface); #endif byteQueueDeinit(&interface->txQueue); byteQueueDeinit(&interface->rxQueue); UartBase->deinit(interface); } #endif /*----------------------------------------------------------------------------*/ static enum Result serialSetCallback(void *object, void (*callback)(void *), void *argument) { struct Serial * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum Result serialGetParam(void *object, enum IfParameter parameter, void *data) { struct Serial * const interface = object; #ifdef CONFIG_PLATFORM_NXP_UART_RC switch ((enum SerialParameter)parameter) { case IF_SERIAL_PARITY: *(uint8_t *)data = (uint8_t)uartGetParity(object); return E_OK; default: break; } #endif switch (parameter) { case IF_AVAILABLE: *(size_t *)data = byteQueueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = byteQueueSize(&interface->txQueue); return E_OK; #ifdef CONFIG_PLATFORM_NXP_UART_RC case IF_RATE: *(uint32_t *)data = uartGetRate(object); return E_OK; #endif default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum Result serialSetParam(void *object, enum IfParameter parameter, const void *data) { struct Serial * const interface = object; #ifdef CONFIG_PLATFORM_NXP_UART_RC switch ((enum SerialParameter)parameter) { case IF_SERIAL_PARITY: uartSetParity(object, (enum SerialParity)(*(const uint8_t *)data)); return E_OK; default: break; } switch (parameter) { case IF_RATE: { struct UartRateConfig rateConfig; const enum Result res = uartCalcRate(object, *(const uint32_t *)data, &rateConfig); if (res == E_OK) { interface->rate = *(const uint32_t *)data; uartSetRate(object, rateConfig); } return res; } default: return E_INVALID; } #else (void)interface; (void)parameter; (void)data; return E_INVALID; #endif } /*----------------------------------------------------------------------------*/ static size_t serialRead(void *object, void *buffer, size_t length) { struct Serial * const interface = object; irqDisable(interface->base.irq); const size_t read = byteQueuePopArray(&interface->rxQueue, buffer, length); irqEnable(interface->base.irq); return read; } /*----------------------------------------------------------------------------*/ static size_t serialWrite(void *object, const void *buffer, size_t length) { struct Serial * const interface = object; LPC_UART_Type * const reg = interface->base.reg; const uint8_t *bufferPosition = buffer; size_t written = 0; irqDisable(interface->base.irq); /* Check transmitter state */ if ((reg->LSR & LSR_THRE) && byteQueueEmpty(&interface->txQueue)) { /* Transmitter is idle so fill TX FIFO */ const size_t bytesToWrite = MIN(length, TX_FIFO_SIZE); for (; written < bytesToWrite; ++written) reg->THR = *bufferPosition++; length -= written; } /* Fill TX queue with the rest of data */ if (length) written += byteQueuePushArray(&interface->txQueue, bufferPosition, length); irqEnable(interface->base.irq); return written; }
/*----------------------------------------------------------------------------*/ static enum result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum result res; assert(config->event < GPTIMER_EVENT_END); timer->event = config->event ? config->event : GPTIMER_MATCH0; --timer->event; /* Call base class constructor */ if ((res = GpTimerBase->init(object, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; reg->MCR = 0; updateFrequency(timer, config->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_GPTIMER_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif /* Timer is disabled by default */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_GPTIMER_PM pmUnregister(interface); #endif GpTimerBase->deinit(timer); } /*----------------------------------------------------------------------------*/ static void tmrCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static void tmrSetEnabled(void *object, bool state) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Stop the timer */ reg->TCR = 0; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); if (state) { /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); reg->TCR = TCR_CEN; } } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock((const struct GpTimerBase *)timer); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { updateFrequency(object, frequency); }
/*----------------------------------------------------------------------------*/ static enum Result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; assert(config); const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum Result res; assert(config->event < GPTIMER_EVENT_END); /* Call base class constructor */ if ((res = GpTimerBase->init(timer, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; timer->event = (config->event ? config->event : GPTIMER_MATCH0) - 1; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; timer->frequency = config->frequency; gpTimerSetFrequency(&timer->base, timer->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Reset the timer after reaching the match register value */ reg->MCR = MCR_RESET(timer->event); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM if ((res = pmRegister(powerStateHandler, timer)) != E_OK) return res; #endif /* Clear timer reset flag, but do not enable */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_GPTIMER_NO_DEINIT static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM pmUnregister(timer); #endif GpTimerBase->deinit(timer); } #endif /*----------------------------------------------------------------------------*/ static void tmrEnable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); /* Start the timer */ reg->TCR = TCR_CEN; } /*----------------------------------------------------------------------------*/ static void tmrDisable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = 0; } /*----------------------------------------------------------------------------*/ static void tmrSetCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock(&timer->base); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { struct GpTimer * const timer = object; timer->frequency = frequency; gpTimerSetFrequency(&timer->base, timer->frequency); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetOverflow(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return (reg->MR[timer->event] + 1) & getMaxValue(timer); } /*----------------------------------------------------------------------------*/ static void tmrSetOverflow(void *object, uint32_t overflow) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(overflow <= getMaxValue(timer)); reg->MR[timer->event] = overflow - 1; } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetValue(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return reg->TC; } /*----------------------------------------------------------------------------*/ static void tmrSetValue(void *object, uint32_t value) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(value <= reg->MR[timer->event]); reg->PC = 0; reg->TC = value; }
/*----------------------------------------------------------------------------*/ static enum result i2cInit(void *object, const void *configBase) { const struct I2cSlaveConfig * const config = configBase; const struct I2cBaseConfig baseConfig = { .channel = config->channel, .scl = config->scl, .sda = config->sda }; struct I2cSlave * const interface = object; enum result res; /* Call base class constructor */ if ((res = I2cBase->init(object, &baseConfig)) != E_OK) return res; interface->cache = malloc(config->size); if (!interface->cache) return E_MEMORY; memset(interface->cache, 0, config->size); interface->base.handler = interruptHandler; interface->callback = 0; interface->external = 0; interface->internal = 0; interface->size = config->size; interface->state = STATE_IDLE; LPC_I2C_Type * const reg = interface->base.reg; /* Clear all flags */ reg->CONCLR = CONCLR_AAC | CONCLR_SIC | CONCLR_STAC | CONCLR_I2ENC; #ifdef CONFIG_I2C_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); irqEnable(interface->base.irq); /* Enable I2C interface */ reg->CONSET = CONSET_AA | CONSET_I2EN; return E_OK; } /*----------------------------------------------------------------------------*/ static void i2cDeinit(void *object) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; reg->CONCLR = CONCLR_I2ENC; /* Disable I2C interface */ #ifdef CONFIG_I2C_PM pmUnregister(interface); #endif irqDisable(interface->base.irq); free(interface->cache); I2cBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result i2cCallback(void *object, void (*callback)(void *), void *argument) { struct I2cSlave * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result i2cGet(void *object, enum ifOption option, void *data) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; switch (option) { case IF_ADDRESS: *(uint16_t *)data = ADR_ADDRESS_VALUE(reg->ADR0); return E_OK; case IF_POSITION: *(uint32_t *)data = interface->internal; return E_OK; case IF_STATUS: return interface->state != STATE_IDLE ? E_BUSY : E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result i2cSet(void *object, enum ifOption option, const void *data) { struct I2cSlave * const interface = object; LPC_I2C_Type * const reg = interface->base.reg; switch (option) { case IF_ADDRESS: if (*(const uint16_t *)data <= 127) { reg->ADR0 = ADR_ADDRESS(*(const uint16_t *)data); return E_OK; } else return E_VALUE; case IF_POSITION: if (*(const uint32_t *)data < interface->size) { interface->internal = *(const uint32_t *)data; return E_OK; } else return E_VALUE; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t i2cRead(void *object, void *buffer, size_t length) { struct I2cSlave * const interface = object; const uint8_t * const position = interface->cache + interface->internal; uint16_t left = interface->size - interface->internal; if (!length) return 0; if (length < left) { left = length; interface->internal += length; } else interface->internal = 0; memcpy(buffer, position, left); return left; } /*----------------------------------------------------------------------------*/ static size_t i2cWrite(void *object, const void *buffer, size_t length) { struct I2cSlave * const interface = object; uint8_t * const position = interface->cache + interface->internal; uint16_t left = interface->size - interface->internal; if (!length) return 0; if (length < left) { left = length; interface->internal += length; } else interface->internal = 0; memcpy(position, buffer, left); return left; }
/*----------------------------------------------------------------------------*/ static enum result canInit(void *object, const void *configBase) { const struct CanConfig * const config = configBase; const struct CanBaseConfig baseConfig = { .channel = config->channel, .rx = config->rx, .tx = config->tx }; struct Can * const interface = object; enum result res; /* Call base class constructor */ if ((res = CanBase->init(object, &baseConfig)) != E_OK) return res; interface->base.handler = interruptHandler; interface->callback = 0; interface->timer = config->timer; interface->mode = MODE_LISTENER; const size_t poolSize = config->rxBuffers + config->txBuffers; res = queueInit(&interface->pool, sizeof(struct CanMessage *), poolSize); if (res != E_OK) return res; res = queueInit(&interface->rxQueue, sizeof(struct CanMessage *), config->rxBuffers); if (res != E_OK) return res; res = queueInit(&interface->txQueue, sizeof(struct CanMessage *), config->txBuffers); if (res != E_OK) return res; interface->poolBuffer = malloc(sizeof(struct CanStandardMessage) * poolSize); struct CanStandardMessage *message = interface->poolBuffer; for (size_t index = 0; index < poolSize; ++index) { queuePush(&interface->pool, &message); ++message; } LPC_CAN_Type * const reg = interface->base.reg; reg->MOD = MOD_RM; /* Reset CAN */ reg->IER = 0; /* Disable Receive Interrupt */ reg->GSR = 0; /* Reset error counter */ interface->rate = config->rate; reg->BTR = calcBusTimings(interface, interface->rate); /* Disable Reset mode and activate Listen Only mode */ reg->MOD = MOD_LOM; LPC_CANAF->AFMR = AFMR_AccBP; //FIXME #ifdef CONFIG_CAN_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif irqSetPriority(interface->base.irq, config->priority); /* Enable interrupts on message reception and bus error */ reg->IER = IER_RIE | IER_BEIE; return E_OK; } /*----------------------------------------------------------------------------*/ static void canDeinit(void *object) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; /* Disable all interrupts */ reg->IER = 0; #ifdef CONFIG_CAN_PM pmUnregister(interface); #endif queueDeinit(&interface->txQueue); queueDeinit(&interface->rxQueue); CanBase->deinit(interface); } /*----------------------------------------------------------------------------*/ static enum result canCallback(void *object, void (*callback)(void *), void *argument) { struct Can * const interface = object; interface->callbackArgument = argument; interface->callback = callback; return E_OK; } /*----------------------------------------------------------------------------*/ static enum result canGet(void *object, enum ifOption option, void *data) { struct Can * const interface = object; switch (option) { case IF_AVAILABLE: *(size_t *)data = queueSize(&interface->rxQueue); return E_OK; case IF_PENDING: *(size_t *)data = queueSize(&interface->txQueue); return E_OK; case IF_RATE: *(uint32_t *)data = interface->rate; return E_OK; default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static enum result canSet(void *object, enum ifOption option, const void *data) { struct Can * const interface = object; LPC_CAN_Type * const reg = interface->base.reg; switch ((enum canOption)option) { case IF_CAN_ACTIVE: changeMode(interface, MODE_ACTIVE); return E_OK; case IF_CAN_LISTENER: changeMode(interface, MODE_LISTENER); return E_OK; case IF_CAN_LOOPBACK: changeMode(interface, MODE_LOOPBACK); return E_OK; default: break; } switch (option) { case IF_RATE: { const uint32_t rate = *(const uint32_t *)data; interface->rate = rate; reg->MOD |= MOD_RM; /* Enable Reset mode */ reg->BTR = calcBusTimings(interface, rate); reg->MOD &= ~MOD_RM; return E_OK; } default: return E_INVALID; } } /*----------------------------------------------------------------------------*/ static size_t canRead(void *object, void *buffer, size_t length) { assert(length % sizeof(struct CanStandardMessage) == 0); struct Can * const interface = object; struct CanStandardMessage *output = buffer; size_t read = 0; while (read < length && !queueEmpty(&interface->rxQueue)) { struct CanMessage *input; const irqState state = irqSave(); queuePop(&interface->rxQueue, &input); memcpy(output, input, sizeof(*output)); queuePush(&interface->pool, &input); irqRestore(state); read += sizeof(*output); ++output; } return read; }