“Hello World!”, I’ve got the CY8CKIT-049 (CY8C4245AXI-483) to put out some data over UART. It’s way from finished, I still have to incorporate all the code into the library, but we’re getting somewhere.

Previously, I’ve been setting up the Internal Main Oscillator (IMO). But for now, I’ll keep it running at it’s default speed of 24 MHz. Now, I’m interested into deriving a clock from this main clock to run a peripheral, in this case, Serial Communication Block 0 (SCB0).

In the clocking mechanism of the PSoC 4100/4200 family, we find Integer dividers Fractional dividers. I’ll start at the Integer dividers. We find three dividers, A, B and C, each have four units. We can cascade A, B and C. For now, I’ll only look at the Integer divider taking the main clock. Mostly because I find the description of the Fractional divider in the TRM kinda vague, and finding out how it works will require some more time to test things. Let’s keep things simple. Just write the number we want to divide our clock through and set the enable bit,

This is some prelimary code, which I should clean up later when I put it in a library. (As I used the addressed of the peripherals, yay for magic numbers)

void clk_set_divider(int divider_abc, int divider_n, int value) {
    volatile uint32_t* clk = 0x40020000 + (0x04*divider_n) + (0x40 * divider_abc);
    *clk = value | 1 << 31; // write value and set enable bit
}

Now we generate our clock, we have to direct it to our peripheral. There is a list of peripherals and their numbers in the Architecture TRM

void clk_select(int peripheral, int divider_abc, int divider_n) {
    volatile uint32_t* sel = 0x40020200;
    sel[peripheral] = (divider_abc + 1)<< 4 | divider_n;
}

Now, we can configure all (integer) clock dividers and assign them to peripherals. I am running the microcontroller at its default speed of 24 MHz. I wish to communicate at a sample rate of 115200 bps. The SCB will use an oversampling of 8. So, for the divider value, I do (24000000/115200) / 8 ≈ 26.

Let's say we want to use the second divider of divider block B, we do

	clk_set_divider(1, 2, 26);
	clk_select(2,1,2);				

Now we have to configure the Serial Communication Block. The SCB can do either UART, I2C or SPI. To specify UART, we need to write 2 at shifted 24 bits. Furthermore we need to specify an amount of oversampling. For UART the valid range is 8 to 16. In this example I will use 8. (As I have done in the calculation above)

	SCB_CTRL(SCB0_BASE) = 0;	// Reset whatever it was
	SCB_CTRL(SCB0_BASE) |= 0x02 << 24; // UART mode
	SCB_CTRL(SCB0_BASE) |= 7; // 7+1 = 8 times oversampling,  minimum for UART

Furthermore, we need to configure how we would like to use the UART. We want to use "Standard mode" (other options are IrDA and SmartCard). Furthermore, we need to configure the stop bits and parity. It seems our SCB supports an asymmetric configuration here, as we need to configure this for both TX and RX.

	SCB_UART_CTRL(SCB0_BASE) = 0 ; // Normal UART Mode
	SCB_UART_TX_CTRL(SCB0_BASE) = 1; // 1 stop bit, no parity
	SCB_UART_RX_CTRL(SCB0_BASE) = 1; // 1 stop bit, no parity

Finally, we need to configure we want 8 databits, this is an option that goes for all the serial protocols. Again, we need to set this in both directions, and enable receiving, sending, and the whole block

	SCB_TX_CTRL(SCB0) = 0; // reset
	SCB_TX_CTRL(SCB0) |= 8; // Data width 8 bits
	SCB_TX_CTRL(SCB0) |= (1 << 31); // Enable TX

	SCB_RX_CTRL(SCB0) = 0; // reset
	SCB_RX_CTRL(SCB0) |= 8; // Data width 8 bits
	SCB_RX_CTRL(SCB0) |= (1 << 31); // Enable RX

	SCB_CTRL(SCB0_BASE) |= (1 << 31); // enable scb

But we're not done yet. Even though the peripheral is now configured, it hasn't been connected to any pins yet. For this, we have to look at yet another peripheral, which I haven't covered yet in my library. It is called "High Speed I/O Matrix" (HSIOM). For each port, there is a register. Each port has 8 pins, and for each pin there are four bytes, so this will fit in a 32 bit register. The value we need to write for the SCB is 9. SCB0 maps to P4.0 and P4.1, so, we write 0x99 to the register, and put those pins in push-pull mode.

	MMIO32(0x40010010) = ( MMIO32(0x40010010) &  0xFFFFFF00 ) | 0x99;
	gpio_set_mode(GPIO_PORT4, GPIO_DM_0_1, 0b11); // P4.0 and P4.1 in push-pull mode

Now, we're ready to say hello to the world!

	char * hello = "Hello World!\r\n";
	int i = 0;
	while (hello[i]) 
		if (!(SCB_TX_FIFO_STATUS(SCB0) & 0x111)) // Check for empty transmit buffer
			SCB_TX_FIFO_WR(SCB0) = hello[i++]; // Write to buffer

Now this isn't perfect yet. The hardware has an 8 bit transmit buffer. But when it's full, it seems I cannot detect yet correctly when I can write data again, truncating my data at 8 bytes. However, when checking the transmit buffer to be empty, rather then checking whether there is room, the transmission is correct.

So I have some data transmitted over the UART. Now I have to clean up everything and make some nice library functions to configure it all.