mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
bogdanm
Date:
Mon Aug 05 14:12:34 2013 +0300
Revision:
13:0645d8841f51
Child:
15:4892fe388435
Update mbed sources to revision 64

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 13:0645d8841f51 1 /* mbed Microcontroller Library
bogdanm 13:0645d8841f51 2 * Copyright (c) 2006-2013 ARM Limited
bogdanm 13:0645d8841f51 3 *
bogdanm 13:0645d8841f51 4 * Licensed under the Apache License, Version 2.0 (the "License");
bogdanm 13:0645d8841f51 5 * you may not use this file except in compliance with the License.
bogdanm 13:0645d8841f51 6 * You may obtain a copy of the License at
bogdanm 13:0645d8841f51 7 *
bogdanm 13:0645d8841f51 8 * http://www.apache.org/licenses/LICENSE-2.0
bogdanm 13:0645d8841f51 9 *
bogdanm 13:0645d8841f51 10 * Unless required by applicable law or agreed to in writing, software
bogdanm 13:0645d8841f51 11 * distributed under the License is distributed on an "AS IS" BASIS,
bogdanm 13:0645d8841f51 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
bogdanm 13:0645d8841f51 13 * See the License for the specific language governing permissions and
bogdanm 13:0645d8841f51 14 * limitations under the License.
bogdanm 13:0645d8841f51 15 */
bogdanm 13:0645d8841f51 16 #include "serial_api.h"
bogdanm 13:0645d8841f51 17
bogdanm 13:0645d8841f51 18 // math.h required for floating point operations for baud rate calculation
bogdanm 13:0645d8841f51 19 #include <math.h>
bogdanm 13:0645d8841f51 20
bogdanm 13:0645d8841f51 21 #include <string.h>
bogdanm 13:0645d8841f51 22
bogdanm 13:0645d8841f51 23 #include "cmsis.h"
bogdanm 13:0645d8841f51 24 #include "pinmap.h"
bogdanm 13:0645d8841f51 25 #include "error.h"
bogdanm 13:0645d8841f51 26
bogdanm 13:0645d8841f51 27 /******************************************************************************
bogdanm 13:0645d8841f51 28 * INITIALIZATION
bogdanm 13:0645d8841f51 29 ******************************************************************************/
bogdanm 13:0645d8841f51 30 static const PinMap PinMap_UART_TX[] = {
bogdanm 13:0645d8841f51 31 {PTC4, UART_1, 3},
bogdanm 13:0645d8841f51 32 {PTA2, UART_0, 2},
bogdanm 13:0645d8841f51 33 {PTD5, UART_2, 3},
bogdanm 13:0645d8841f51 34 {PTD3, UART_2, 3},
bogdanm 13:0645d8841f51 35 {NC , NC , 0}
bogdanm 13:0645d8841f51 36 };
bogdanm 13:0645d8841f51 37
bogdanm 13:0645d8841f51 38 static const PinMap PinMap_UART_RX[] = {
bogdanm 13:0645d8841f51 39 {PTC3, UART_1, 3},
bogdanm 13:0645d8841f51 40 {PTA1, UART_0, 2},
bogdanm 13:0645d8841f51 41 {PTD4, UART_2, 3},
bogdanm 13:0645d8841f51 42 {PTD2, UART_2, 3},
bogdanm 13:0645d8841f51 43 {NC , NC , 0}
bogdanm 13:0645d8841f51 44 };
bogdanm 13:0645d8841f51 45
bogdanm 13:0645d8841f51 46 #define UART_NUM 3
bogdanm 13:0645d8841f51 47 static uint32_t serial_irq_ids[UART_NUM] = {0};
bogdanm 13:0645d8841f51 48 static uart_irq_handler irq_handler;
bogdanm 13:0645d8841f51 49
bogdanm 13:0645d8841f51 50 int stdio_uart_inited = 0;
bogdanm 13:0645d8841f51 51 serial_t stdio_uart;
bogdanm 13:0645d8841f51 52
bogdanm 13:0645d8841f51 53 void serial_init(serial_t *obj, PinName tx, PinName rx) {
bogdanm 13:0645d8841f51 54 // determine the UART to use
bogdanm 13:0645d8841f51 55 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 56 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
bogdanm 13:0645d8841f51 57 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
bogdanm 13:0645d8841f51 58 if ((int)uart == NC) {
bogdanm 13:0645d8841f51 59 error("Serial pinout mapping failed");
bogdanm 13:0645d8841f51 60 }
bogdanm 13:0645d8841f51 61
bogdanm 13:0645d8841f51 62 obj->uart = (UARTLP_Type *)uart;
bogdanm 13:0645d8841f51 63 // enable clk
bogdanm 13:0645d8841f51 64 switch (uart) {
bogdanm 13:0645d8841f51 65 case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT);
bogdanm 13:0645d8841f51 66 SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
bogdanm 13:0645d8841f51 67 case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
bogdanm 13:0645d8841f51 68 case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
bogdanm 13:0645d8841f51 69 }
bogdanm 13:0645d8841f51 70 // Disable UART before changing registers
bogdanm 13:0645d8841f51 71 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 13:0645d8841f51 72
bogdanm 13:0645d8841f51 73 switch (uart) {
bogdanm 13:0645d8841f51 74 case UART_0: obj->index = 0; break;
bogdanm 13:0645d8841f51 75 case UART_1: obj->index = 1; break;
bogdanm 13:0645d8841f51 76 case UART_2: obj->index = 2; break;
bogdanm 13:0645d8841f51 77 }
bogdanm 13:0645d8841f51 78
bogdanm 13:0645d8841f51 79 // set default baud rate and format
bogdanm 13:0645d8841f51 80 serial_baud (obj, 9600);
bogdanm 13:0645d8841f51 81 serial_format(obj, 8, ParityNone, 1);
bogdanm 13:0645d8841f51 82
bogdanm 13:0645d8841f51 83 // pinout the chosen uart
bogdanm 13:0645d8841f51 84 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 85 pinmap_pinout(rx, PinMap_UART_RX);
bogdanm 13:0645d8841f51 86
bogdanm 13:0645d8841f51 87 // set rx/tx pins in PullUp mode
bogdanm 13:0645d8841f51 88 pin_mode(tx, PullUp);
bogdanm 13:0645d8841f51 89 pin_mode(rx, PullUp);
bogdanm 13:0645d8841f51 90
bogdanm 13:0645d8841f51 91 obj->uart->C2 |= (UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 13:0645d8841f51 92
bogdanm 13:0645d8841f51 93 if (uart == STDIO_UART) {
bogdanm 13:0645d8841f51 94 stdio_uart_inited = 1;
bogdanm 13:0645d8841f51 95 memcpy(&stdio_uart, obj, sizeof(serial_t));
bogdanm 13:0645d8841f51 96 }
bogdanm 13:0645d8841f51 97 }
bogdanm 13:0645d8841f51 98
bogdanm 13:0645d8841f51 99 void serial_free(serial_t *obj) {
bogdanm 13:0645d8841f51 100 serial_irq_ids[obj->index] = 0;
bogdanm 13:0645d8841f51 101 }
bogdanm 13:0645d8841f51 102
bogdanm 13:0645d8841f51 103 // serial_baud
bogdanm 13:0645d8841f51 104 //
bogdanm 13:0645d8841f51 105 // set the baud rate, taking in to account the current SystemFrequency
bogdanm 13:0645d8841f51 106 //
bogdanm 13:0645d8841f51 107 // The LPC2300 and LPC1700 have a divider and a fractional divider to control the
bogdanm 13:0645d8841f51 108 // baud rate. The formula is:
bogdanm 13:0645d8841f51 109 //
bogdanm 13:0645d8841f51 110 // Baudrate = (1 / PCLK) * 16 * DL * (1 + DivAddVal / MulVal)
bogdanm 13:0645d8841f51 111 // where:
bogdanm 13:0645d8841f51 112 // 1 < MulVal <= 15
bogdanm 13:0645d8841f51 113 // 0 <= DivAddVal < 14
bogdanm 13:0645d8841f51 114 // DivAddVal < MulVal
bogdanm 13:0645d8841f51 115 //
bogdanm 13:0645d8841f51 116 void serial_baud(serial_t *obj, int baudrate) {
bogdanm 13:0645d8841f51 117
bogdanm 13:0645d8841f51 118 // save C2 state
bogdanm 13:0645d8841f51 119 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
bogdanm 13:0645d8841f51 120
bogdanm 13:0645d8841f51 121 // Disable UART before changing registers
bogdanm 13:0645d8841f51 122 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 13:0645d8841f51 123
bogdanm 13:0645d8841f51 124 // [TODO] not hardcode this value
bogdanm 13:0645d8841f51 125 uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
bogdanm 13:0645d8841f51 126
bogdanm 13:0645d8841f51 127 // First we check to see if the basic divide with no DivAddVal/MulVal
bogdanm 13:0645d8841f51 128 // ratio gives us an integer result. If it does, we set DivAddVal = 0,
bogdanm 13:0645d8841f51 129 // MulVal = 1. Otherwise, we search the valid ratio value range to find
bogdanm 13:0645d8841f51 130 // the closest match. This could be more elegant, using search methods
bogdanm 13:0645d8841f51 131 // and/or lookup tables, but the brute force method is not that much
bogdanm 13:0645d8841f51 132 // slower, and is more maintainable.
bogdanm 13:0645d8841f51 133 uint16_t DL = PCLK / (16 * baudrate);
bogdanm 13:0645d8841f51 134
bogdanm 13:0645d8841f51 135 // set BDH and BDL
bogdanm 13:0645d8841f51 136 obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
bogdanm 13:0645d8841f51 137 obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
bogdanm 13:0645d8841f51 138
bogdanm 13:0645d8841f51 139 // restore C2 state
bogdanm 13:0645d8841f51 140 obj->uart->C2 |= c2_state;
bogdanm 13:0645d8841f51 141 }
bogdanm 13:0645d8841f51 142
bogdanm 13:0645d8841f51 143 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
bogdanm 13:0645d8841f51 144 uint8_t m10 = 0;
bogdanm 13:0645d8841f51 145
bogdanm 13:0645d8841f51 146 // save C2 state
bogdanm 13:0645d8841f51 147 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
bogdanm 13:0645d8841f51 148
bogdanm 13:0645d8841f51 149 // Disable UART before changing registers
bogdanm 13:0645d8841f51 150 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 13:0645d8841f51 151
bogdanm 13:0645d8841f51 152 // 8 data bits = 0 ... 9 data bits = 1
bogdanm 13:0645d8841f51 153 if ((data_bits < 8) || (data_bits > 9)) {
bogdanm 13:0645d8841f51 154 error("Invalid number of bits (%d) in serial format, should be 8..9\r\n", data_bits);
bogdanm 13:0645d8841f51 155 }
bogdanm 13:0645d8841f51 156 data_bits -= 8;
bogdanm 13:0645d8841f51 157
bogdanm 13:0645d8841f51 158 uint8_t parity_enable, parity_select;
bogdanm 13:0645d8841f51 159 switch (parity) {
bogdanm 13:0645d8841f51 160 case ParityNone: parity_enable = 0; parity_select = 0; break;
bogdanm 13:0645d8841f51 161 case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break;
bogdanm 13:0645d8841f51 162 case ParityEven: parity_enable = 1; parity_select = 0; data_bits++; break;
bogdanm 13:0645d8841f51 163 default:
bogdanm 13:0645d8841f51 164 error("Invalid serial parity setting\r\n");
bogdanm 13:0645d8841f51 165 return;
bogdanm 13:0645d8841f51 166 }
bogdanm 13:0645d8841f51 167
bogdanm 13:0645d8841f51 168 // 1 stop bits = 0, 2 stop bits = 1
bogdanm 13:0645d8841f51 169 if ((stop_bits != 1) && (stop_bits != 2)) {
bogdanm 13:0645d8841f51 170 error("Invalid stop bits specified\r\n");
bogdanm 13:0645d8841f51 171 }
bogdanm 13:0645d8841f51 172 stop_bits -= 1;
bogdanm 13:0645d8841f51 173
bogdanm 13:0645d8841f51 174 // 9 data bits + parity
bogdanm 13:0645d8841f51 175 if (data_bits == 2) {
bogdanm 13:0645d8841f51 176 // only uart0 supports 10 bit communication
bogdanm 13:0645d8841f51 177 if (obj->index != 0) {
bogdanm 13:0645d8841f51 178 error("Invalid number of bits (9) to be used with parity\r\n");
bogdanm 13:0645d8841f51 179 }
bogdanm 13:0645d8841f51 180 data_bits = 0;
bogdanm 13:0645d8841f51 181 m10 = 1;
bogdanm 13:0645d8841f51 182 }
bogdanm 13:0645d8841f51 183
bogdanm 13:0645d8841f51 184 // data bits, parity and parity mode
bogdanm 13:0645d8841f51 185 obj->uart->C1 = ((data_bits << 4)
bogdanm 13:0645d8841f51 186 | (parity_enable << 1)
bogdanm 13:0645d8841f51 187 | (parity_select << 0));
bogdanm 13:0645d8841f51 188
bogdanm 13:0645d8841f51 189 // enable 10bit mode if needed
bogdanm 13:0645d8841f51 190 if (obj->index == 0) {
bogdanm 13:0645d8841f51 191 obj->uart->C4 &= ~UARTLP_C4_M10_MASK;
bogdanm 13:0645d8841f51 192 obj->uart->C4 |= (m10 << UARTLP_C4_M10_SHIFT);
bogdanm 13:0645d8841f51 193 }
bogdanm 13:0645d8841f51 194
bogdanm 13:0645d8841f51 195 // stop bits
bogdanm 13:0645d8841f51 196 obj->uart->BDH &= ~UART_BDH_SBNS_MASK;
bogdanm 13:0645d8841f51 197 obj->uart->BDH |= (stop_bits << UART_BDH_SBNS_SHIFT);
bogdanm 13:0645d8841f51 198
bogdanm 13:0645d8841f51 199 // restore C2 state
bogdanm 13:0645d8841f51 200 obj->uart->C2 |= c2_state;
bogdanm 13:0645d8841f51 201 }
bogdanm 13:0645d8841f51 202
bogdanm 13:0645d8841f51 203 /******************************************************************************
bogdanm 13:0645d8841f51 204 * INTERRUPTS HANDLING
bogdanm 13:0645d8841f51 205 ******************************************************************************/
bogdanm 13:0645d8841f51 206 static inline void uart_irq(uint8_t status, uint32_t index) {
bogdanm 13:0645d8841f51 207 if (serial_irq_ids[index] != 0) {
bogdanm 13:0645d8841f51 208 if (status & UART_S1_TDRE_MASK)
bogdanm 13:0645d8841f51 209 irq_handler(serial_irq_ids[index], TxIrq);
bogdanm 13:0645d8841f51 210
bogdanm 13:0645d8841f51 211 if (status & UART_S1_RDRF_MASK)
bogdanm 13:0645d8841f51 212 irq_handler(serial_irq_ids[index], RxIrq);
bogdanm 13:0645d8841f51 213 }
bogdanm 13:0645d8841f51 214 }
bogdanm 13:0645d8841f51 215
bogdanm 13:0645d8841f51 216 void uart0_irq() {
bogdanm 13:0645d8841f51 217 uart_irq(UART0->S1, 0);
bogdanm 13:0645d8841f51 218 if (UART0->S1 & UART_S1_OR_MASK)
bogdanm 13:0645d8841f51 219 UART0->S1 |= UART_S1_OR_MASK;
bogdanm 13:0645d8841f51 220 }
bogdanm 13:0645d8841f51 221 void uart1_irq() {uart_irq(UART1->S1, 1);}
bogdanm 13:0645d8841f51 222 void uart2_irq() {uart_irq(UART2->S1, 2);}
bogdanm 13:0645d8841f51 223
bogdanm 13:0645d8841f51 224 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
bogdanm 13:0645d8841f51 225 irq_handler = handler;
bogdanm 13:0645d8841f51 226 serial_irq_ids[obj->index] = id;
bogdanm 13:0645d8841f51 227 }
bogdanm 13:0645d8841f51 228
bogdanm 13:0645d8841f51 229 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
bogdanm 13:0645d8841f51 230 IRQn_Type irq_n = (IRQn_Type)0;
bogdanm 13:0645d8841f51 231 uint32_t vector = 0;
bogdanm 13:0645d8841f51 232 switch ((int)obj->uart) {
bogdanm 13:0645d8841f51 233 case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
bogdanm 13:0645d8841f51 234 case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
bogdanm 13:0645d8841f51 235 case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
bogdanm 13:0645d8841f51 236 }
bogdanm 13:0645d8841f51 237
bogdanm 13:0645d8841f51 238 if (enable) {
bogdanm 13:0645d8841f51 239 switch (irq) {
bogdanm 13:0645d8841f51 240 case RxIrq: obj->uart->C2 |= (UART_C2_RIE_MASK); break;
bogdanm 13:0645d8841f51 241 case TxIrq: obj->uart->C2 |= (UART_C2_TIE_MASK); break;
bogdanm 13:0645d8841f51 242 }
bogdanm 13:0645d8841f51 243 NVIC_SetVector(irq_n, vector);
bogdanm 13:0645d8841f51 244 NVIC_EnableIRQ(irq_n);
bogdanm 13:0645d8841f51 245
bogdanm 13:0645d8841f51 246 } else { // disable
bogdanm 13:0645d8841f51 247 int all_disabled = 0;
bogdanm 13:0645d8841f51 248 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
bogdanm 13:0645d8841f51 249 switch (irq) {
bogdanm 13:0645d8841f51 250 case RxIrq: obj->uart->C2 &= ~(UART_C2_RIE_MASK); break;
bogdanm 13:0645d8841f51 251 case TxIrq: obj->uart->C2 &= ~(UART_C2_TIE_MASK); break;
bogdanm 13:0645d8841f51 252 }
bogdanm 13:0645d8841f51 253 switch (other_irq) {
bogdanm 13:0645d8841f51 254 case RxIrq: all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0; break;
bogdanm 13:0645d8841f51 255 case TxIrq: all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0; break;
bogdanm 13:0645d8841f51 256 }
bogdanm 13:0645d8841f51 257 if (all_disabled)
bogdanm 13:0645d8841f51 258 NVIC_DisableIRQ(irq_n);
bogdanm 13:0645d8841f51 259 }
bogdanm 13:0645d8841f51 260 }
bogdanm 13:0645d8841f51 261
bogdanm 13:0645d8841f51 262 /******************************************************************************
bogdanm 13:0645d8841f51 263 * READ/WRITE
bogdanm 13:0645d8841f51 264 ******************************************************************************/
bogdanm 13:0645d8841f51 265 int serial_getc(serial_t *obj) {
bogdanm 13:0645d8841f51 266 while (!serial_readable(obj));
bogdanm 13:0645d8841f51 267 return obj->uart->D;
bogdanm 13:0645d8841f51 268 }
bogdanm 13:0645d8841f51 269
bogdanm 13:0645d8841f51 270 void serial_putc(serial_t *obj, int c) {
bogdanm 13:0645d8841f51 271 while (!serial_writable(obj));
bogdanm 13:0645d8841f51 272 obj->uart->D = c;
bogdanm 13:0645d8841f51 273 }
bogdanm 13:0645d8841f51 274
bogdanm 13:0645d8841f51 275 int serial_readable(serial_t *obj) {
bogdanm 13:0645d8841f51 276 // check overrun
bogdanm 13:0645d8841f51 277 if (obj->uart->S1 & UART_S1_OR_MASK) {
bogdanm 13:0645d8841f51 278 obj->uart->S1 |= UART_S1_OR_MASK;
bogdanm 13:0645d8841f51 279 }
bogdanm 13:0645d8841f51 280 return (obj->uart->S1 & UART_S1_RDRF_MASK);
bogdanm 13:0645d8841f51 281 }
bogdanm 13:0645d8841f51 282
bogdanm 13:0645d8841f51 283 int serial_writable(serial_t *obj) {
bogdanm 13:0645d8841f51 284 // check overrun
bogdanm 13:0645d8841f51 285 if (obj->uart->S1 & UART_S1_OR_MASK) {
bogdanm 13:0645d8841f51 286 obj->uart->S1 |= UART_S1_OR_MASK;
bogdanm 13:0645d8841f51 287 }
bogdanm 13:0645d8841f51 288 return (obj->uart->S1 & UART_S1_TDRE_MASK);
bogdanm 13:0645d8841f51 289 }
bogdanm 13:0645d8841f51 290
bogdanm 13:0645d8841f51 291 void serial_clear(serial_t *obj) {
bogdanm 13:0645d8841f51 292 }
bogdanm 13:0645d8841f51 293
bogdanm 13:0645d8841f51 294 void serial_pinout_tx(PinName tx) {
bogdanm 13:0645d8841f51 295 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 296 }
bogdanm 13:0645d8841f51 297
bogdanm 13:0645d8841f51 298 void serial_break_set(serial_t *obj) {
bogdanm 13:0645d8841f51 299 obj->uart->C2 |= UART_C2_SBK_MASK;
bogdanm 13:0645d8841f51 300 }
bogdanm 13:0645d8841f51 301
bogdanm 13:0645d8841f51 302 void serial_break_clear(serial_t *obj) {
bogdanm 13:0645d8841f51 303 obj->uart->C2 &= ~UART_C2_SBK_MASK;
bogdanm 13:0645d8841f51 304 }
bogdanm 13:0645d8841f51 305